碰到过类似这题几次都做不出,只因为始终不理解
这题值得推荐的理由:离散化,树形转化为数组的线性结构,离线做法,树状数组,排序后边插入边询问等多种处理技巧
1.深搜后树上的某点的子树变成数组的一个区间,网上有人估计写挫了,说会爆栈,我不会,
最好不用vector,会TLE,这题数据挺强的,后来改了邻接表过了,事实证明,邻接表还是时间空间都有很好效果的做法
2.讲询问按右端点排序,每次插入更新,如果有这个是某个询问的右端点,就询问
3.在插入到某点i是,第k(1<=k<=i)表示k到i的答案,要明白:
每插入新的一点,改变的只有插入的这个数,设这个数P出现的位置是P0,P1,P2...Pj-k-1,Pj-k,Pj-k+1....Pj-1,
如果询问的左端点在(Pj-k-1,Pj-k],右端点在i,P就凑够K次
现在在Pj=i插入新的数P,就变成如果询问的左端点在(Pj-k,Pj-k+1],P凑够K次,
而左端点在(Pj-k-1,Pj-k]的P出现的次数变成K+1,不是答案,
所以树状数组的操作是(Pj-k-1,Pj-k] 区间-1,(Pj-k,Pj-k+1]区间+1,然后询问左端点的值就好了(因为树状数组上第k位表示k到i的答案)
可见要用到的操作:区间更新,单点询问,用第二类树状数组
~~1.离散化的时候搞错,一直RE不止
~~2vector用的过多导致TLE
~~3.最后还PE了。。。
果然历经艰辛啊
#include <iostream> #include <map> #include <algorithm> #include <vector> #include <cstring> #include <cstdio> #include <cstdlib> #include <stack> using namespace std; #define N 105000 int edge[N*2],head[N*2],adj[N*2],e; int dfn[N],low[N],val[N],n,K,w[N],cnt,q; vector<int>vec[N]; int vis[N]; struct Query { int l,r,id; }que[N]; bool cmp(Query left,Query right) { return left.r==right.r?left.l<right.l:left.r<right.r; } int ans[N],r[N];int b[N]; bool cmp2(int left,int right) { return w[left]==w[right]?left<right:w[left]<w[right]; } void addedge(int u,int v) { edge[e]=v;adj[e]=head[u];head[u]=e++; } void dfs(int u,int fa) { dfn[u]=++cnt;val[cnt]=w[u]; for(int i=head[u];i!=-1;i=adj[i]) if(edge[i]!=fa) dfs(edge[i],u); low[u]=cnt; } int lowbit(int x) { return x&(-x); } void update(int x,int v) { while(x<=n) { b[x]+=v; x+=lowbit(x); } } int getsum(int x) { int ret=0; while(x>0) { ret+=b[x]; x-=lowbit(x); } return ret; } int main () { //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); int test;scanf("%d",&test); for(int k=1;k<=test;++k) { scanf("%d%d",&n,&K); for(int i=0;i<=n;++i) head[i]=-1,b[i]=0; cnt=e=0; for(int i=1;i<=n;++i) scanf("%d",&w[i]),r[i]=i; sort(r+1,r+1+n,cmp2); int pre=w[r[1]]-1; for(int i=1;i<=n;++i) if(pre!=w[r[i]]) pre=w[r[i]],w[r[i]]=++cnt; else w[r[i]]=cnt; int u,v; for(int i=1;i<n;++i) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } cnt=0; dfs(1,-1); scanf("%d",&q); for(int i=1;i<=q;++i) { scanf("%d",&u); que[i].l=dfn[u]; que[i].r=low[u]; que[i].id=i; } sort(que+1,que+1+q,cmp); for(int i=0;i<=n;++i) vec[i].clear(),vec[i].push_back(0); int size,q_index=1; for(int i=1;i<=n;++i) { vec[val[i]].push_back(i); size=vec[val[i]].size()-1; if(size>=K) { if(size>K) { update(vec[val[i]][size-K-1]+1,-1); update(vec[val[i]][size-K]+1,1); } update(vec[val[i]][size-K]+1,1); update(vec[val[i]][size-K+1]+1,-1); } while(que[q_index].r==i&&q_index<=q) { ans[que[q_index].id]=getsum(que[q_index].l); q_index++; } } printf("Case #%d:\n",k); for(int i=1;i<=q;++i) printf("%d\n",ans[i]); if(k<test) printf("\n"); } //system("pause"); return 0; }