問題の意味
ツリーは、各ノード\は、(私は\)一定容量有する\(K_I \) (のみインストールすることができる\(K_I \)色); \(Mの\)操作、各時間\(Xを\ )する\(1)\の色の経路上の全ての点をプラス\(C \) 、変更操作がどのように多くの異なる色を完了した後、各ノードに問い合わせ\((N、M、K_I \当量10 ^ 5) \)
考え
30pts小さなデータを直接暴力をジャンプ
さらにそこ40pts \(K_I = 10 ^ 5 \ ) と比較することができるテール雨
その答えは、サブツリー内の操作の影響の点で見ることができます
この問題は、明らかに色(レンジセグメントツリーを)維持するか、メンテナンス時間(連続的な変更操作)、および範囲のセグメントツリーを考慮することはできません\(k個\)制約、唯一40ptsので、メンテナンス時間を考えます
したがって添字セグメントツリーメンテナンス、2つの値の保守ポイントとして動作のシーケンスを変更することにより:\(SIZ \) :サブツリー操作の数; \(SUM \) :実際のサブツリーを動作寄与の数
実際の操作に何を貢献していますか?同じ色の二つの動作が発生した場合には寄与しない後、同じサブツリーは、操作は、つまり、場所を取るだろう\(SIZ + 1 \)が、\(合計\)変わりません
これらの二つの変数を使用すると、セグメントツリーはに従って(K_I \)\二分法を見つけることができます(私は\)\をノードの回答
しかしとしてではないすべての点は、セグメントツリーを構築するそのサブツリーの動作のみを考慮のポイント、ツリーラインがボトムアップ組み合わせることができるので、彼は木のヒューリスティック合併になった、操作のすべての複雑さがないことを確認します重い息子に基づいて何の問題の複雑さを保証することはできません
で、この質問の似たアイデア、それがすることです(トライ\)\時間のツリーラインへ
時間複雑\(O(nlog ^ 2n個) \)
コード
#include<bits/stdc++.h>
#define N 100005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m,q,k[N],ans[N];
int sum[N<<2],size[N<<2],sig[N<<2];
int son[N],fa[N],t[N<<2];
vector< pair<int,int> > co[N];
map<int,int> mp;//颜色还有负数,cao
int colsum=0;
struct Edge
{
int next,to;
}edge[N<<1];int head[N],cnt=1;
void add_edge(int from,int to)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
head[from]=cnt;
}
template <class T>
void read(T &x)
{
char c; int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void dfs1(int rt)
{
size[rt]=1;
for(int i=head[rt];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[rt]) continue;
fa[v]=rt;
dfs1(v);
size[rt]+=size[v];
if(size[son[rt]]<size[v]) son[rt]=v;
}
}
void pd(int rt)
{
if(!sig[rt]) return;
sig[rt<<1]=sig[rt<<1|1]=1;
size[rt<<1]=size[rt<<1|1]=sum[rt<<1]=sum[rt<<1|1]=0;
sig[rt]=0;
}
void modify(int rt,int l,int r,int x,int val,int siz)//颜色数量,时间数量
{
if(l==r) { sum[rt]+=val; size[rt]+=siz; return; }
int mid=(l+r)>>1;
pd(rt);
if(x<=mid) modify(rt<<1,l,mid,x,val,siz);
else modify(rt<<1|1,mid+1,r,x,val,siz);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
size[rt]=size[rt<<1]+size[rt<<1|1];
}
int query(int rt,int l,int r,int k)
{
if(k<=0) return 0;
if(l==r) return sum[rt];
int mid=(l+r)>>1;
pd(rt);
if(size[rt<<1]<=k) return sum[rt<<1] + query(rt<<1|1,mid+1,r,k-size[rt<<1]);
return query(rt<<1,l,mid,k);
}
void add(int rt)
{
for(int i=0,c=co[rt].size();i<c;++i)
{
int col=co[rt][i].first,tim=co[rt][i].second;
if(!t[col])//第一次加入该颜色
{
t[col]=tim;
modify(1,1,m,tim,1,0);
}
else if(t[col]>tim)
{
modify(1,1,m,t[col],-1,0);
modify(1,1,m,tim,1,0);
t[col]=tim;
}
modify(1,1,m,tim,0,1);
}
}
void clr(int rt)
{
size[1]=sum[1]=sig[1]=1;
for(int i=0,c=co[rt].size();i<c;++i) t[co[rt][i].first]=0;
}
void cv(int x,int y)
{
for(int i=0,c=co[y].size();i<c;++i) co[x].push_back(co[y][i]);
co[y].clear();
}
void dfs(int rt)
{
for(int i=head[rt];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[rt] || v==son[rt]) continue;
dfs(v); clr(v);
}
if(son[rt]) dfs(son[rt]);
add(rt);
for(int i=head[rt];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[rt] || v==son[rt]) continue;
add(v);
}
ans[rt]=query(1,1,m,k[rt]);
if(son[rt])
{
cv(son[rt],rt);
swap(co[rt],co[son[rt]]);
// cv(rt,son[rt]);直接这样复杂度是错的qwq
for(int i=head[rt];i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=fa[rt]) cv(rt,v);
}
}
}
int main()
{
freopen("ac.in","r",stdin);
freopen("ac.out","w",stdout);
read(n);
for(int i=1;i<n;++i)
{
int x,y;
read(x);read(y);
add_edge(x,y);
add_edge(y,x);
}
dfs1(1);
for(int i=1;i<=n;++i) read(k[i]);
read(m);
for(int i=1;i<=m;++i)
{
int x,c;
read(x);read(c);
if(!mp[c]) mp[c]=++colsum;
c=mp[c];
co[x].push_back(make_pair(c,i));
}
memset(size,0,sizeof(size));
dfs(1);
read(q);
while(q--)
{
int x; read(x);
printf("%d\n",ans[x]);
}
return 0;
}