bzoj 4999: This Problem Is Too Simple!
Description
给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。
Input
第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
下面一行N个整数,表示初始时每个节点的初始值。
接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。
Output
对于每个Q输出单独一行表示所求的答案。
Sample Input
5 6
10 20 30 40 50
1 2
1 3
3 4
3 5
Q 2 3 40
C 1 40
Q 2 3 40
Q 4 5 30
C 3 10
Q 4 5 30
10 20 30 40 50
1 2
1 3
3 4
3 5
Q 2 3 40
C 1 40
Q 2 3 40
Q 4 5 30
C 3 10
Q 4 5 30
Sample Output
0
1
1
0
1
1
0
————————————————————————————
这道题我写的扫描线
我们把一个询问(u->v)拆成四个
设根为1
询问的答案就是1->u + 1->v - 1->lca(u,v) 1-fa[lca]
然后修改的影响范围只有这个点的子树 这个可以用dfs序+树状数组实现
然后我们每一种权值建一棵树(权值需要离散化) 当然因为如果每次都初始化树状数组肯定会T
这里我利用了时间戳 这样之后就解决问题了 就是代码可能有点复杂QAQ
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> const int M=1e6+7,mod=9875321; int read(){ int ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();} return ans*f; } int n,m,k,v[M],l[M],r[M],pos[M]; int first[M],cnt,ans[M],mark[M]; struct node{int to,next;}e[2*M]; void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;} void insert(int a,int b){ins(a,b); ins(b,a);} int dep[M],f[M][25],sum; void dfs(int x){ l[x]=pos[x]=++sum; for(int i=1;(1<<i)<=dep[x];i++) f[x][i]=f[f[x][i-1]][i-1]; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(!dep[now]){ dep[now]=dep[x]+1; f[now][0]=x; dfs(now); } }r[x]=sum; } int find(int x,int y){ if(dep[x]<dep[y]) std::swap(x,y); int d=dep[x]-dep[y]; for(int i=0;(1<<i)<=d;i++) if(1<<i&d) x=f[x][i]; if(x==y) return x; for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } struct P{int s,x,T;}; std::vector<P>e1[M]; struct Q{int l,r,T;}; std::vector<Q>e2[M]; int star[mod],cnth; struct H{int to,next;}hash[M]; int get(int x){ int w=x%mod; for(int i=star[w];i;i=hash[i].next) if(hash[i].to==x) return i; cnth++; hash[cnth].to=x; hash[cnth].next=star[w]; star[w]=cnth; return cnth; } char c[5]; int s[M],now[M]; int lowbit(int x){return x&-x;} void add(int x,int ss){ while(x<=n){ if(now[x]!=k) now[x]=k,s[x]=0; s[x]+=ss; x+=lowbit(x); } } int query(int x){ int ans=0; while(x){ if(now[x]==k) ans+=s[x]; x-=lowbit(x); } return ans; } int main(){ n=read(); m=read(); for(int i=1;i<=n;i++){ v[i]=get(read()); e1[v[i]].push_back((P){1,i,0}); } int x,y; for(int i=1;i<n;i++) x=read(),y=read(),insert(x,y); dep[1]=1; dfs(1); for(int i=1;i<=m;i++){ scanf("%s",c); if(c[0]=='C'){ x=read(); k=get(read()); if(v[x]==k) continue; e1[k].push_back((P){1,x,i}); e1[v[x]].push_back((P){-1,x,i}); v[x]=k; } else{ mark[i]=1; x=read(); y=read(); k=get(read()); e2[k].push_back((Q){x,y,i}); } } for(k=1;k<=cnth;k++){ int now=0; P* h1=e1[k].data(); Q* h2=e2[k].data(); for(int i=0;i<e2[k].size();i++){ while(now<e1[k].size()&&h1[now].T<=h2[i].T){ add(l[h1[now].x],h1[now].s); add(r[h1[now].x]+1,-h1[now].s); now++; } int id=h2[i].T; ans[id]+=query(pos[h2[i].l]); ans[id]+=query(pos[h2[i].r]); int lca=find(h2[i].l,h2[i].r),fa=f[lca][0]; ans[id]-=query(pos[lca]); ans[id]-=query(pos[fa]); } } for(int i=1;i<=m;i++)if(mark[i]) printf("%d\n",ans[i]); return 0; }