【树链剖分】【离线操作】【SDOI2014】旅行
(rhj ak ioi!!!)
【题目描述】
【输入】
输入的第一行包含整数 N,Q 依次表示城市数和事件数。
接下来 N 行,第 i+1行两个整数 Wi ,Ci 依次表示记录开始之前,城市 i 的评级和信仰。
接下来 N−1 行每行两个整数 x,y 表示一条双向道路。
接下来 Q 行,每行一个操作,格式如上所述。
【输出】
对每个 QS 和 QM 事件,输出一行,表示旅行者记下的数字。
【样例输入】
5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4
【样例输出】
8
9
11
3
提示
对所有的数据,N,Q≤10^5, C≤10^5 ,对所有 QS 和 QM 事件,起点和终点城市的信仰相同;在任意时刻,城市的评级总是不大于 10^4的正整数,且宗教值不大于 C。
【思路】
这道题似乎可以动态开点。不过这里采用离线做法。(本来我以为离线做法做不了 )这道题的离线思路和[SDOI2008]郁闷的小J差不多,依次处理每个宗教。对于宗教的修改才做,我们可以把节点在原宗教上的影响赋为0,然后再进行新宗教上的单点修改(即拆成两个单点修改)。然后就只需要保证处理完每个宗教以后删除所有的节点(这个删除操作只需要删除最终树上该宗教的点,就可以保证时间复杂度)。
代码:(260行的丑代码)
#include<bits/stdc++.h>
#define re register
#define lc (p<<1)
#define rc (p<<1|1)
#define len(p) (t[p].r-t[p].l+1)
using namespace std;
long long n,m,a,b;
struct node{
long long u,v;
}e[2000001];
struct tree{
long long l,r;
long long sum;
long long mx;
}t[4000001];
struct que{
long long col;
long long ans;
long long u,v;
long long opt;
long long tim;
}q[1000001];
/*
opt:
2 单点修改
3 询问sum
4 询问mx
*/
long long f[1000001];
long long nxp[2000001];
long long cnt=0;
inline void add(long long u,long long v)
{
e[++cnt].u=u;
e[cnt].v=v;
nxp[cnt]=f[u];
f[u]=cnt;
}
long long son[1000001];
long long siz[1000001];
long long dep[1000001];
long long fa[1000001];
long long top[1000001];
long long seg[1000001];
long long rev[1000001];
void dfs1(long long u,long long ff)
{
dep[u]=dep[ff]+1;
fa[u]=ff;
siz[u]=1;
for(long long re i=f[u];i;i=nxp[i])
{
long long v=e[i].v;
if(!dep[v])
{
dfs1(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])son[u]=v;
}
}
}
long long tot=0;
void dfs2(long long u)
{
if(son[u])
{
seg[son[u]]=++tot;
rev[tot]=son[u];
top[son[u]]=top[u];
dfs2(son[u]);
}
for(long long re i=f[u];i;i=nxp[i])
{
long long v=e[i].v;
if(!top[v])
{
top[v]=v;
seg[v]=++tot;
rev[tot]=v;
dfs2(v);
}
}
}
long long sum=0,mx=0,id=0;
long long val[1000001];
inline void pushup(long long p)
{
t[p].sum=t[lc].sum+t[rc].sum;
t[p].mx=max(t[lc].mx,t[rc].mx);
}
void build(long long p,long long l,long long r)
{
t[p].l=l;
t[p].r=r;
if(l==r)return;
long long mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
void change(long long p,long long k,long long v)
{
long long l=t[p].l,r=t[p].r;
if(l==r)
{
t[p].mx=t[p].sum=v;
return;
}
long long mid=(l+r)>>1;
if(k<=mid)change(lc,k,v);
if(k>mid)change(rc,k,v);
pushup(p);
}
void ask(long long p,long long ql,long long qr)
{
long long l=t[p].l,r=t[p].r;
if(ql<=l&&qr>=r)
{
sum+=t[p].sum;
mx=max(mx,t[p].mx);
return;
}
long long mid=(l+r)>>1;
if(ql<=mid)ask(lc,ql,qr);
if(qr>mid)ask(rc,ql,qr);
}
long long root=1;
int tt=0;
void query(long long x,long long y)
{
long long fx=top[x],fy=top[y];
sum=0;mx=-0x7f7f7f7f;
while(fx!=fy)
{
if(dep[fx]<dep[fy])
{
swap(fx,fy);
swap(x,y);
}
ask(1,seg[fx],seg[x]);
x=fa[fx];
fx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
ask(1,seg[x],seg[y]);
}
int num=0;
long long col[100001];
inline bool cmp1(que a,que b)
{
if(a.col==b.col)return a.tim<b.tim;
return a.col<b.col;
}
inline bool cmp2(que a,que b)
{
return a.tim<b.tim;
}
int main()
{
scanf("%lld",&n);scanf("%lld",&m);
for(long long re i=1;i<=n;i++)
{
scanf("%lld%lld",&val[i],&col[i]);
q[++num].opt=2;
q[num].tim=0;
q[num].col=col[i];
q[num].u=i;
q[num].ans=val[i];
}
for(int re i=1;i<n;i++)
{
scanf("%lld%lld",&a,&b);
add(a,b);
add(b,a);
}
rev[1]=tot=seg[1]=top[1]=1;
dfs1(1,0);
dfs2(1);
build(1,1,tot);
while(m--)
{
char c[10];
scanf("\n%s%lld%lld",c+1,&a,&b);
if(c[1]=='C'&&c[2]=='C')
{
q[++num].u=a;
q[num].tim=++tt;
q[num].col=col[a];
q[num].ans=0;
q[num].opt=2;
col[a]=b;
q[++num].u=a;
q[num].tim=++tt;
q[num].col=col[a];
q[num].ans=val[a];
q[num].opt=2;
}
if(c[1]=='C'&&c[2]=='W')
{
q[++num].u=a;
q[num].tim=++tt;
q[num].col=col[a];
q[num].ans=b;
q[num].opt=2;
val[a]=b;
}
if(c[1]=='Q'&&c[2]=='S')
{
q[++num].u=a;
q[num].col=col[a];
q[num].v=b;
q[num].opt=3;
q[num].tim=++tt;
}
if(c[1]=='Q'&&c[2]=='M')
{
q[++num].u=a;
q[num].col=col[a];
q[num].v=b;
q[num].opt=4;
q[num].tim=++tt;
}
}
for(int re i=1;i<=n;i++)
{
q[++num].u=i;
q[num].tim=tt+1;
q[num].col=col[i];
q[num].ans=0;
q[num].opt=2;
}
sort(q+1,q+num+1,cmp1);
for(int re i=1;i<=num;i++)
{
int opt=q[i].opt;
if(opt==2)
change(1,seg[q[i].u],q[i].ans);
if(opt==3)
{
query(q[i].u,q[i].v);
q[i].ans=sum;
}
if(opt==4)
{
query(q[i].u,q[i].v);
q[i].ans=mx;
}
}
sort(q+1,q+num+1,cmp2);
for(int re i=1;i<=num;i++)
{
int opt=q[i].opt;
if(opt==3||opt==4)
{
printf("%lld\n",q[i].ans);
}
}
}