4999: This Problem Is Too Simple!

xiaoxiao2021-02-27  118

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 Sample Output

0

1

1

0

出题人不要求强制在线就可以乱搞了。。 离散化肯定是要的。。 想我这种垃圾就只会树剖,就剖一下,对于每一个x动态开点建线段树就好了 就是把普通树剖传多一个树根编号而已。。改一下动态开点。。 时间复杂度 O(qlognlogn) 其实看起来我觉得有点大。。 然而跑得挺快的

#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> using namespace std; const int N=100005; const int Q=200005; int n,q; int a[N]; int A[N+Q],Cnt=0; struct qq { int x,y,last; }e[N*2];int num,last[N]; void init (int x,int y) { num++; e[num].x=x;e[num].y=y; e[num].last=last[x]; last[x]=num; } struct qy{int i,j,x;}ask[Q];//询问 void Init () { num=0;memset(last,-1,sizeof(last)); scanf("%d%d",&n,&q); for (int u=1;u<=n;u++) { scanf("%d",&a[u]); A[++Cnt]=a[u]; } for (int u=1;u<n;u++) { int x,y; scanf("%d%d",&x,&y); init(x,y);init(y,x); } for (int u=1;u<=q;u++) { char ss[N]; scanf("%s",ss); if (ss[0]=='C')//修改 { scanf("%d%d",&ask[u].i,&ask[u].x); ask[u].j=-1; A[++Cnt]=ask[u].x; } else scanf("%d%d%d",&ask[u].i,&ask[u].j,&ask[u].x); } } int tot[N],f[N],dep[N],son[N]; void dfs (int x,int fa) { f[x]=fa;tot[x]=1; for (int u=last[x];u!=-1;u=e[u].last) { int y=e[u].y; if (y==fa) continue; dep[y]=dep[x]+1;dfs(y,x); tot[x]+=tot[y]; if (tot[son[x]]<tot[y]) son[x]=y; } } int ys[N],top[N],num1; void dfs1 (int x,int y) { top[x]=y;ys[x]=++num1; if (son[x]!=0) dfs1(son[x],y); for (int u=last[x];u!=-1;u=e[u].last) { int y=e[u].y; if (y==son[x]||y==f[x]) continue; dfs1(y,y); } } int Find (int x) { int l=1,r=Cnt; while (l<=r) { int mid=(l+r)>>1; if (A[mid]==x) return mid; if (A[mid]>x) r=mid-1; else l=mid+1; } return 0;//防止不存在的情况 } int root[N+Q],ooo=0; struct qt { int s1,s2; int c; }s[(N+Q)*20*2]; void change (int &now,int l,int r,int x,int y)//这条边变一下 { if (now==0) now=++ooo; if (l==r) { s[now].c+=y; return ; } int mid=(l+r)>>1; if (x<=mid) change(s[now].s1,l,mid,x,y); else change(s[now].s2,mid+1,r,x,y); s[now].c=s[s[now].s1].c+s[s[now].s2].c; } void prepare ()//各种预处理 { sort(A+1,A+1+Cnt); /*for (int u=1;u<=Cnt;u++) printf("%d ",A[u]); printf("\n");*/ int ccnt=1; for (int u=2;u<=Cnt;u++) if (A[u]!=A[ccnt]) A[++ccnt]=A[u]; Cnt=ccnt; // for (int u=1;u<=Cnt;u++) printf("%d ",A[u]); dep[1]=1;dfs(1,0); num1=0;dfs1(1,1); for (int u=1;u<=n;u++) change(root[Find(a[u])],1,num1,ys[u],1); } int get (int now,int l,int r,int L,int R) { //printf("now:%d c:%d l:%d r:%d L:%d R:%d\n",now,s[now].c,l,r,L,R); if (now==0) return 0; if (l==L&&r==R) return s[now].c; if (s[now].c==0)//以前荒废的 return 0; int s1=s[now].s1,s2=s[now].s2; int mid=(l+r)>>1; if (R<=mid) return get(s1,l,mid,L,R); else if (L>mid) return get(s2,mid+1,r,L,R); else return get(s1,l,mid,L,mid)+get(s2,mid+1,r,mid+1,R); } int get_ans (int x,int y,int z) { if (z==0) return 0; // printf("%d %d %d\n",x,y,z); int tx=top[x],ty=top[y]; if (dep[tx]>dep[ty]) {swap(tx,ty);swap(x,y);} int ans=0; while (tx!=ty) { ans=ans+get(root[z],1,num1,ys[ty],ys[y]); y=f[ty];ty=top[y]; if (dep[tx]>dep[ty]) {swap(tx,ty);swap(x,y);} } if (dep[x]>dep[y]) swap(x,y); ans=ans+get(root[z],1,num1,ys[x],ys[y]); return ans; } void solve () { for (int u=1;u<=q;u++) { if (ask[u].j==-1)//是一个修改操作 { change(root[Find(a[ask[u].i])],1,num1,ys[ask[u].i],-1);//这个点在x这颗树上不见了 a[ask[u].i]=ask[u].x; change(root[Find(a[ask[u].i])],1,num1,ys[ask[u].i],1);//这个点在x这颗树上出现了 } else { //printf("%d %d\n",ask[u].x,Find(ask[u].x)); printf("%d\n",get_ans(ask[u].i,ask[u].j,Find(ask[u].x))); } } } int main() { Init(); prepare(); solve(); return 0; }
转载请注明原文地址: https://www.6miu.com/read-15822.html

最新回复(0)