调了一天,恶心死我了……作者的题解水的一b……
测试点1~6:
暴力修改查询即可,期望得分30。
测试点7~14:
k=1e5,相当于没有限制,那么对于树上每个点建权值线段树,线段树合并即可。
期望的分40,结合算法1 70分。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #define MAXN 100010 6 #define LL long long 7 #define int LL 8 #define ma(x,y) memset(x,y,sizeof(x)) 9 using namespace std; 10 struct edge 11 { 12 int u,v,nxt; 13 #define u(x) ed[x].u 14 #define v(x) ed[x].v 15 #define n(x) ed[x].nxt 16 }ed[MAXN*2]; 17 int first[MAXN],num_e; 18 #define f(x) first[x] 19 int n,m,k[MAXN],Q,tc[MAXN]; 20 struct tree 21 { 22 int ls,rs,sum; 23 #define ls(x) tr[x].ls 24 #define rs(x) tr[x].rs 25 #define sum(x) tr[x].sum 26 }tr[MAXN*200]; 27 int cnt,T[MAXN]; 28 int sum[1010][1010],fa[MAXN],maxc; 29 void add(int &x,int l,int r,int L,int R) 30 { 31 if(!x)x=++cnt; 32 if(l==r){sum(x)|=1;return;} 33 int mid=(l+r)>>1; 34 if(L<=mid)add(ls(x),l,mid,L,R); 35 if(R>mid) add(rs(x),mid+1,r,L,R); 36 sum(x)=sum(ls(x))+sum(rs(x)); 37 } 38 int ask(int x,int l,int r,int L,int R) 39 { 40 if(l>=L&&r<=R)return sum(x); 41 int mid=(l+r)>>1,ans=0; 42 if(L<=mid)ans+=ask(ls(x),l,mid,L,R); 43 if(R>mid) ans+=ask(rs(x),mid+1,r,L,R); 44 return ans; 45 } 46 int merge(int x,int y) 47 { 48 if(!x||!y)return x+y; 49 ls(x)=merge(ls(x),ls(y)); 50 rs(x)=merge(rs(x),rs(y)); 51 if(!ls(x)&&!rs(x))sum(x)=sum(x)|sum(y); 52 else sum(x)=sum(ls(x))+sum(rs(x)); 53 return x; 54 } 55 int ans[MAXN],x[MAXN],c[MAXN]; 56 void dfs(int x,int fa) 57 { 58 for(int i=f(x);i;i=n(i)) 59 if(v(i)!=fa) 60 { 61 dfs(v(i),x); 62 ans[v(i)]=ask(T[v(i)],1,maxc,1,maxc); 63 T[x]=merge(T[x],T[v(i)]); 64 } 65 } 66 void dfs2(int x,int ff) 67 { 68 fa[x]=ff; 69 for(int i=f(x);i;i=n(i)) 70 if(v(i)!=ff) 71 dfs2(v(i),x); 72 } 73 inline int read(); 74 inline void adde(int u,int v); 75 signed main() 76 { 77 n=read();int tu,tv; 78 for(int i=1;i<n;i++) 79 { 80 tu=read(),tv=read(); 81 adde(tu,tv),adde(tv,tu); 82 } 83 for(int i=1;i<=n;i++)k[i]=read(); 84 m=read(); 85 dfs2(1,0); 86 if(n<=1000&&m<=1000)//暴力 87 { 88 LL tem,ac;LL x,c; 89 for(int i=1;i<=m;i++) 90 { 91 x=read();c=read(); 92 maxc=max(maxc,c); 93 tem=x; 94 while(tem) 95 { 96 if(sum[tem][0]<k[tem]) 97 sum[tem][0]++,sum[tem][c]++; 98 tem=fa[tem]; 99 } 100 } 101 Q=read(); 102 for(int i=1;i<=Q;i++) 103 { 104 tem=read();ac=0; 105 for(int j=1;j<=maxc;j++) 106 if(sum[tem][j]!=0)ac++; 107 printf("%lld ",ac); 108 } 109 return 0; 110 } 111 for(int i=1;i<=m;i++) 112 { 113 x[i]=read(),c[i]=read(),tc[i]=c[i]; 114 maxc=max(maxc,c[i]); 115 } 116 sort(tc+1,tc+1+m);maxc=m; 117 int ooo=unique(tc+1,tc+1+m)-tc-1; 118 for(int i=1;i<=m;i++) 119 c[i]=lower_bound(tc+1,tc+ooo+1,c[i])-tc; 120 for(int i=1;i<=m;i++) 121 add(T[x[i]],1,maxc,c[i],c[i]); 122 dfs(1,0); 123 Q=read(); 124 ans[1]=ask(T[1],1,maxc,1,maxc); 125 for(int i=1;i<=Q;i++) 126 { 127 x[i]=read();printf("%lld ",ans[x[i]]); 128 } 129 } 130 inline int read() 131 { 132 int s=0,f=1;char a=getchar(); 133 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar(); } 134 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 135 return s*f; 136 } 137 inline void adde(int u,int v) 138 { 139 ++num_e; 140 u(num_e)=u; 141 v(num_e)=v; 142 n(num_e)=f(u); 143 f(u)=num_e; 144 }
测试点15~20:
最恶心的几个点,用到了树上启发式合并+树链剖分思想。
考虑以时间为线段树下标建立权值线段树,维护这段时间内小球的颜色种类数以及小球总数,用一个桶记录每个颜色出现的最早时间。对于每个节点建立一个vector,将关于这个节点的操作color,time二元组扔到这个节点的vector中。
首先一边dfs求出每个点的重儿子,要用重儿子来保证复杂度,证明见这里。
这里先说一下不保证复杂度但是好理解而且可以救回来的思路:
然后第二遍dfs统计答案:先处理儿子(注意每次要清空桶,但是不要memset),然后将这个节点的所有操作扔到他的重儿子的vector中,互换(相当于将重儿子的操作扔到这个节点),然后枚举儿子,将其他儿子的操作合并,接下来就是统计这个点的答案了:首先确保此时桶是空的,然后枚举这个节点vector中的操作,如果当前小球未出现过直接更新线段树,如果在一个更晚的时间出现则在那个时间种类数减1,这个时间种类数+1。最后个数加1.然后说一下线段树的查询操作,和主席树的思想类似(直接上代码):
1 int ask(int x,int l,int r,int num) 2 { 3 if(num<=0)return 0; 4 if(l==r)return sum(x); 5 int ans=0,mid=(l+r)>>1; 6 if(num(ls(x))<=num) 7 { 8 ans+=sum(ls(x)); 9 ans+=ask(rs(x),mid+1,r,num-num(ls(x))); 10 return ans; 11 } 12 else return ask(ls(x),l,mid,num); 13 }
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #define MAXN 100010 7 #define LL long long 8 #define MP(a,b) make_pair(a,b) 9 #define ma(x) memest(x,0,sizeof(x)) 10 using namespace std; 11 struct edge 12 { 13 int u,v,nxt; 14 #define u(x) ed[x].u 15 #define v(x) ed[x].v 16 #define n(x) ed[x].nxt 17 }ed[MAXN*2]; 18 int first[MAXN],num_e; 19 #define f(x) first[x] 20 int n,m,k[MAXN],Q,tc[MAXN]; 21 vector<pair<int,int> >cz[MAXN]; 22 struct tree 23 { 24 int ls,rs,sum,num; 25 #define ls(x) tr[x].ls 26 #define rs(x) tr[x].rs 27 #define sum(x) tr[x].sum 28 #define num(x) tr[x].num 29 }tr[MAXN*1000]; 30 int cnt,T[MAXN],maxc; 31 int ans[MAXN],x[MAXN],c[MAXN]; 32 int t[MAXN]; 33 int son[MAXN],size[MAXN]; 34 void add(int &x,int l,int r,int t,int tx,int y) 35 { 36 if(!x)x=++cnt; 37 if(l==r){sum(x)+=tx;num(x)+=y;return;} 38 int mid=(l+r)>>1; 39 if(t<=mid)add(ls(x),l,mid,t,tx,y); 40 else add(rs(x),mid+1,r,t,tx,y); 41 sum(x)=sum(ls(x))+sum(rs(x)); 42 num(x)=num(ls(x))+num(rs(x)); 43 } 44 int ask(int x,int l,int r,int num) 45 { 46 if(num<=0)return 0; 47 if(l==r)return sum(x); 48 int ans=0,mid=(l+r)>>1; 49 if(num(ls(x))<=num) 50 { 51 ans+=sum(ls(x)); 52 ans+=ask(rs(x),mid+1,r,num-num(ls(x))); 53 return ans; 54 } 55 else return ask(ls(x),l,mid,num); 56 } 57 void merge(int x,int y) 58 { 59 for(int i=0;i<cz[y].size();i++) 60 cz[x].push_back(cz[y][i]); 61 cz[y].clear(); 62 } 63 void clear(int x) 64 { 65 for(int i=0;i<cz[x].size();i++) 66 t[cz[x][i].first]=0; 67 } 68 void dfs2(int x,int fa) 69 { 70 for(int i=f(x);i;i=n(i)) 71 if(v(i)!=fa) 72 { 73 dfs2(v(i),x); 74 clear(v(i)); 75 } 76 if(son[x]) 77 { 78 merge(son[x],x); 79 swap(cz[son[x]],cz[x]); 80 } 81 for(int i=f(x);i;i=n(i)) 82 if(v(i)!=fa)merge(x,v(i)); 83 for(int i=0;i<cz[x].size();i++) 84 { 85 int t1=cz[x][i].first,t2=cz[x][i].second; 86 if(!t[t1]) 87 add(T[x],1,m,t2,1,0),t[t1]=t2; 88 else if(t[t1]>t2) 89 { 90 add(T[x],1,m,t[t1],-1,0); 91 add(T[x],1,m,t2,1,0); 92 t[t1]=t2; 93 } 94 add(T[x],1,m,t2,0,1); 95 } 96 ans[x]=ask(T[x],1,m,k[x]); 97 } 98 inline int read(); 99 void dfs(int x,int fa); 100 inline void adde(int u,int v); 101 signed main() 102 { 103 // freopen("in.txt","r",stdin); 104 105 n=read();int tu,tv; 106 for(int i=1;i<n;i++) 107 { 108 tu=read(),tv=read(); 109 adde(tu,tv),adde(tv,tu); 110 } 111 for(int i=1;i<=n;i++)k[i]=read(); 112 m=read(); 113 for(int i=1;i<=m;i++) 114 { 115 x[i]=read(),c[i]=read(),tc[i]=c[i]; 116 maxc=max(maxc,c[i]); 117 } 118 sort(tc+1,tc+1+m);maxc=m; 119 int ooo=unique(tc+1,tc+1+m)-tc-1; 120 for(int i=1;i<=m;i++) 121 c[i]=lower_bound(tc+1,tc+ooo+1,c[i])-tc; 122 for(int i=1;i<=m;i++) 123 cz[x[i]].push_back(MP(c[i],i)); 124 dfs(1,0); 125 dfs2(1,0); 126 Q=read(); 127 for(int i=1;i<=Q;i++) 128 x[i]=read(),printf("%d ",ans[x[i]]); 129 } 130 inline int read() 131 { 132 int s=0,f=1;char a=getchar(); 133 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar(); } 134 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 135 return s*f; 136 } 137 inline void adde(int u,int v) 138 { 139 ++num_e; 140 u(num_e)=u; 141 v(num_e)=v; 142 n(num_e)=f(u); 143 f(u)=num_e; 144 } 145 void dfs(int x,int fa) 146 { 147 size[x]=1; 148 for(int i=f(x);i;i=n(i)) 149 if(v(i)!=fa) 150 { 151 dfs(v(i),x); 152 size[x]+=size[v(i)]; 153 if(size[v(i)]>size[son[x]])son[x]=v(i); 154 } 155 }
到这里就结束了,然后你应该就会发现你T30了,因为以上算法是不保证时间复杂度的,原因在于处理重儿子后清空桶花费了过长时间。但是如果不清空桶下面的答案查询就会出错,那怎么办呢?
其实可以在处理完所有轻儿子后在处理重儿子,此后不清空桶,而是直接T[x]=T[son[x]](根节点),直接从重儿子的线段树上开始修改,这样时间复杂度就有保证了。还有一点是这样要在最后才把重儿子的操作合并。
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #define MAXN 100010 7 #define LL long long 8 #define int LL 9 #define MP(a,b) make_pair(a,b) 10 #define ma(x) memest(x,0,sizeof(x)) 11 using namespace std; 12 struct edge 13 { 14 int u,v,nxt; 15 #define u(x) ed[x].u 16 #define v(x) ed[x].v 17 #define n(x) ed[x].nxt 18 }ed[MAXN*2]; 19 int first[MAXN],num_e; 20 #define f(x) first[x] 21 int n,m,k[MAXN],Q,tc[MAXN]; 22 vector<pair<int,int> >cz[MAXN]; 23 struct tree 24 { 25 int ls,rs,sum,num; 26 #define ls(x) tr[x].ls 27 #define rs(x) tr[x].rs 28 #define sum(x) tr[x].sum 29 #define num(x) tr[x].num 30 }tr[MAXN*200]; 31 int cnt,T[MAXN],maxc; 32 int ans[MAXN],x[MAXN],c[MAXN]; 33 int t[MAXN]; 34 int son[MAXN],size[MAXN]; 35 void add(int &x,int l,int r,int t,int tx,int y) 36 { 37 if(!x)x=++cnt; 38 if(l==r){sum(x)+=tx;num(x)+=y;return;} 39 int mid=(l+r)>>1; 40 if(t<=mid)add(ls(x),l,mid,t,tx,y); 41 else add(rs(x),mid+1,r,t,tx,y); 42 sum(x)=sum(ls(x))+sum(rs(x)); 43 num(x)=num(ls(x))+num(rs(x)); 44 } 45 int ask(int x,int l,int r,int num) 46 { 47 if(num<=0)return 0; 48 if(l==r)return sum(x); 49 int ans=0,mid=(l+r)>>1; 50 if(num(ls(x))<=num) 51 { 52 ans+=sum(ls(x)); 53 ans+=ask(rs(x),mid+1,r,num-num(ls(x))); 54 return ans; 55 } 56 else return ask(ls(x),l,mid,num); 57 } 58 void merge(int x,int y) 59 { 60 for(int i=0;i<cz[y].size();i++) 61 cz[x].push_back(cz[y][i]); 62 cz[y].clear(); 63 } 64 void clear(int x) 65 { 66 for(int i=0;i<cz[x].size();i++) 67 t[cz[x][i].first]=0; 68 } 69 void dfs2(int x,int fa) 70 { 71 for(int i=f(x);i;i=n(i)) 72 if(v(i)!=fa&&v(i)!=son[x]) 73 { 74 dfs2(v(i),x); 75 clear(v(i)); 76 } 77 if(son[x])dfs2(son[x],x); 78 if(son[x])T[x]=T[son[x]]; 79 for(int i=f(x);i;i=n(i)) 80 if(v(i)!=fa&&v(i)!=son[x])merge(x,v(i)); 81 for(int i=0;i<cz[x].size();i++) 82 { 83 int t1=cz[x][i].first,t2=cz[x][i].second; 84 if(!t[t1])add(T[x],1,m,t2,1,0),t[t1]=t2; 85 else if(t[t1]>t2) 86 { 87 add(T[x],1,m,t[t1],-1,0); 88 add(T[x],1,m,t2,1,0); 89 t[t1]=t2; 90 } 91 add(T[x],1,m,t2,0,1); 92 } 93 ans[x]=ask(T[x],1,m,k[x]); 94 if(son[x]) 95 { 96 merge(son[x],x); 97 swap(cz[son[x]],cz[x]); 98 } 99 } 100 inline int read(); 101 void dfs(int x,int fa); 102 inline void adde(int u,int v); 103 signed main() 104 { 105 // freopen("in.txt","r",stdin); 106 107 n=read();int tu,tv; 108 for(int i=1;i<n;i++) 109 { 110 tu=read(),tv=read(); 111 adde(tu,tv),adde(tv,tu); 112 } 113 for(int i=1;i<=n;i++)k[i]=read(); 114 m=read(); 115 for(int i=1;i<=m;i++) 116 { 117 x[i]=read(),c[i]=read(),tc[i]=c[i]; 118 maxc=max(maxc,c[i]); 119 } 120 sort(tc+1,tc+1+m);maxc=m; 121 int ooo=unique(tc+1,tc+1+m)-tc-1; 122 for(int i=1;i<=m;i++) 123 c[i]=lower_bound(tc+1,tc+ooo+1,c[i])-tc; 124 for(int i=1;i<=m;i++) 125 cz[x[i]].push_back(MP(c[i],i)); 126 dfs(1,0);dfs2(1,0); 127 Q=read(); 128 for(int i=1;i<=Q;i++) 129 x[i]=read(),printf("%lld ",ans[x[i]]); 130 } 131 inline int read() 132 { 133 int s=0,f=1;char a=getchar(); 134 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar(); } 135 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 136 return s*f; 137 } 138 inline void adde(int u,int v) 139 { 140 ++num_e; 141 u(num_e)=u; 142 v(num_e)=v; 143 n(num_e)=f(u); 144 f(u)=num_e; 145 } 146 void dfs(int x,int fa) 147 { 148 size[x]=cz[x].size(); 149 for(int i=f(x);i;i=n(i)) 150 if(v(i)!=fa) 151 { 152 dfs(v(i),x); 153 size[x]+=size[v(i)]; 154 if(size[v(i)]>size[son[x]])son[x]=v(i); 155 } 156 }