HDU 4358
看了题解那个弱化版后,马上就去做了HDU 3333这道题,发现有可用的地方。于是往这方面想,主要是处理如何确定一个数出现K次的问题。想到了从左往右把每个数出现的次数记下来,但感觉不是这样,呃,再看别人做的,真的是这样的--!
主要是处理一个数出现K次后的情况,把每个数出现的位置记录下来,当出现大于等于K次时,假设此时已出现sz个,则把sz-k这个位置加1,把之前的SZ-K-1的位置-2,使之状态是-1(因为之前刚好出现K次时就已加1)。于是当查询到右端点时,求出区间和,+1和-1刚好消去。需要注意的是,当SZ-K-2>=0时,应当把SZ-K-2之前为-1的位置置成0,即加1。这样结果才是正确的。
至于把树映射到数组,很简单,使用DFS+时间戳的方法就可以了,记录每个结点第一次出现的次序以及深搜完以该结点为根的子树的最后一个时间戳即可。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <vector> #define LL __int64 #define lowbit(x) ((x)&(-x)) using namespace std; const int N=100100; const int Q=100100; struct Query{ int l,r,Id; Query(){} Query(int ll,int rr,int d){ l=ll; r=rr; Id=d; } bool operator <(const Query &a)const{ if(r<a.r) return true; return false; } }; Query query[Q]; LL su[N],ans[Q]; int num[N],val[N]; struct Node{ int bgn,en; }; Node node[N]; vector<int>pos[N]; int n,k,q,tot,DEP; struct Edge{ int u,v,next; }edge[N*2]; int head[N]; void addedge(int u,int v){ edge[tot].u=u; edge[tot].v=v; edge[tot].next=head[u]; head[u]=tot++; } LL sum(int x){ if(x==0) return 0; LL s=0; for(;x;x-=lowbit(x)){ s+=su[x]; } return s; } void update(int x,LL w){ for(;x<=n;x+=lowbit(x)) su[x]+=w; } void dfs(int u,int f){ ++DEP; node[u].bgn=DEP; val[DEP]=num[u]; for(int e=head[u];e!=-1;e=edge[e].next){ int v=edge[e].v; if(v!=f){ dfs(v,u); } } node[u].en=DEP; } int main(){ int T,t=0,u,v,cnt=0; scanf("%d",&T); while(++t<=T){ map<int,int>mp; tot=0;DEP=0; cnt=0; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&num[i]); head[i]=-1; su[i]=0; pos[i].clear(); if(!mp[num[i]]) mp[num[i]]=++cnt; } for(int i=1;i<n;i++){ scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs(1,0); scanf("%d",&q); for(int i=1;i<=q;i++){ scanf("%d",&cnt); query[i]=Query(node[cnt].bgn,node[cnt].en,i); } sort(query+1,query+1+q); cnt=1; int sz; for(int i=1;i<=n;i++){ int t=mp[val[i]]; pos[t].push_back(i); sz=pos[t].size(); if(sz>=k){ if(sz==k){ update(pos[t][sz-k],1); } else{ update(pos[t][sz-k-1],-2); update(pos[t][sz-k],1); } if(sz-k-2>=0) update(pos[t][sz-k-2],1); } while(query[cnt].r==i){ ans[query[cnt].Id]=sum(query[cnt].r)-sum(query[cnt].l-1); cnt++; } } printf("Case #%d:\n",t); for(int i=1;i<=q;i++) printf("%I64d\n",ans[i]); if(t<T) puts(""); } return 0; }