トピックリンク
http://acm.hdu.edu.cn/showproblem.php?pid=5390
問題の意味
与えられたA \(N- \)のツリーノードの少し右、\(M \)の操作、次のカテゴリに属している各操作:
- ノードの値を変更する権利。
- 所与のノードのために\(U \) 、検索\(U \)に\(1 \)パス上の服用ノードを\(V \)取得することができ、(val_u⊗val_v\)\最大。
\ (1≤n、m≤10^ ^5,0≤val_i≤109 \)
思考
クエリー\(X \)ルートノードへのパス上のインパクトポイント、ポイントはそのサブツリーを変更答えに影響しますので。検討\(DFS \)ツリーラインを維持するためには、それぞれがそのへの更新変更します\(DFS \)発注間隔を。XOR最大値が自然に行く見つける(トライ\)\木に。私たちは、ツリーラインのセットを使用することができるように(トライ\)\ツリー、ツリーラインの各ノードが維持するために、\(01 \)辞書を更新されてそのDFS発注間隔ツリー内のトライ、すべてのポイントの変更ノードの重みを、ことができます。時間の複雑さがある(32nlog_2n \)\。
クエリ、一つは、怠惰なマークを変更するには、ノードがクエリを行う葉までのすべての方法をプッシュするクエリ時間の場所に位置して2つの方法があり、この方法は非常に大きなスペースのオーバーヘッドです。
別のマークは、このノードの怠惰な、あなたができるだけの線分の木ではありません\(トライ\)ツリーラインパス内の各ノードのために尋ねられたとき、ツリーの削除や挿入、シングルポイントトライ(\ \ )木は、最大値があってもよい貪欲解決されます。
第二の方法は、その後、トライのサイズはに開きます\(32nlog_2n \) 、スーパーメモリになります。このメソッドのコードを添付します
#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e5+10;
vector<int>ma[maxx];
int w[maxx];
struct Trie
{
int trie[32*20*maxx][2],tot;
int sum[32*20*maxx];
void init()
{
tot=0;
trie[0][0]=trie[0][1]=sum[0]=0;
}
void update(int rt,int x,int c)
{
for(int i=31;i>=0;i--)
{
int id=(x>>i)&1;
if(!trie[rt][id])
{
trie[rt][id]=++tot;
trie[tot][0]=trie[tot][1]=sum[tot]=0;
}
rt=trie[rt][id];
sum[rt]+=c;
}
}
int query(int rt,int x)
{
int res=0;
for(int i=31;i>=0;i--)
{
int id=(x>>i)&1;
if(trie[rt][id^1]&&sum[trie[rt][id^1]])rt=trie[rt][id^1],res+=(1<<i);
else rt=trie[rt][id];
}
return res;
}
}trie;
struct Tree
{
int t[maxx<<2],ans;
void build(int l,int r,int rt)
{
t[rt]=++trie.tot;
if(l==r)return;
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
}
void update(int l,int r,int p,int q,int x,int c,int rt)
{
if(p<=l&&r<=q)
{
trie.update(t[rt],x,c);
return;
}
int mid=(l+r)/2;
if(p<=mid)update(l,mid,p,q,x,c,rt*2);
if(q>mid)update(mid+1,r,p,q,x,c,rt*2+1);
}
void query(int l,int r,int x,int c,int rt)
{
ans=max(ans,trie.query(t[rt],c));
if(l==r)return;
int mid=(l+r)/2;
if(x<=mid)query(l,mid,x,c,rt*2);
else query(mid+1,r,x,c,rt*2+1);
}
}tree;
int in[maxx],out[maxx],cnt;
void dfs(int u,int fa)
{
in[u]=++cnt;
for(int i=0;i<ma[u].size();i++)
{
int v=ma[u][i];
if(v==fa)continue;
dfs(v,u);
}
out[u]=cnt;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)ma[i].clear();
int x;
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
ma[x].push_back(i);
ma[i].push_back(x);
}
cnt=0;
dfs(1,0);
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
trie.init();
tree.build(1,n,1);
for(int i=1;i<=n;i++)
tree.update(1,n,in[i],out[i],w[i],1,1);
int op,y;
while(m--)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%d",&x,&y);
tree.update(1,n,in[x],out[x],w[x],-1,1);
w[x]=y;
tree.update(1,n,in[x],out[x],w[x],1,1);
}
else
{
scanf("%d",&x);
tree.ans=0;
tree.query(1,n,in[x],w[x],1);
printf("%d\n",tree.ans);
}
}
}
return 0;
}
木は、各ノードについて、様々な関連の削除、挿入および更新の答えが行うオフ我々は、セグメントを考慮することができるように、ツリーラインの各ノードをマークしない怠惰なので、第二の方法は、実際に独立していますライン上で再びそれを行うためです。(ベクトル\)\ノードを節約するために、すべての操作、および最終的には全体の歯セグメントツリートラバーサル、すべてのノードがクリアされます\(トライ\)にツリー、保守運用ノード順次\(トライ\)上。だから、唯一維持する必要が\(トライを\)にスペースの複雑さを最適化するために、(32N \)\。
#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e5+10;
vector<int>ma[maxx];
int w[maxx];
struct node{int op,x,c;};
int ans[maxx];
struct Trie
{
int trie[32*maxx][2],tot;
int sum[32*maxx];
void init()
{
tot=0;
trie[0][0]=trie[0][1]=sum[0]=0;
}
void update(int x,int c)
{
int rt=0;
for(int i=31;i>=0;i--)
{
int id=(x>>i)&1;
if(!trie[rt][id])
{
trie[rt][id]=++tot;
trie[tot][0]=trie[tot][1]=sum[tot]=0;
}
rt=trie[rt][id];
sum[rt]+=c;
}
}
int query(int x)
{
int rt=0,res=0;
for(int i=31;i>=0;i--)
{
int id=(x>>i)&1;
if(trie[rt][id^1]&&sum[trie[rt][id^1]])rt=trie[rt][id^1],res+=(1<<i);
else rt=trie[rt][id];
}
return res;
}
}trie;
struct Tree
{
vector<node>t[maxx<<2];
void build(int l,int r,int rt)
{
t[rt].clear();
if(l==r)return;
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
}
void update(int l,int r,int p,int q,int x,int c,int rt)
{
if(p<=l&&r<=q)
{
t[rt].push_back(node{0,x,c});
return;
}
int mid=(l+r)/2;
if(p<=mid)update(l,mid,p,q,x,c,rt*2);
if(q>mid)update(mid+1,r,p,q,x,c,rt*2+1);
}
void query(int l,int r,int x,int c,int id,int rt)
{
t[rt].push_back(node{1,c,id});
if(l==r)return;
int mid=(l+r)/2;
if(x<=mid)query(l,mid,x,c,id,rt*2);
else query(mid+1,r,x,c,id,rt*2+1);
}
void getans(int l,int r,int rt)
{
trie.init();
for(int i=0;i<t[rt].size();i++)
{
int op=t[rt][i].op,x=t[rt][i].x,c=t[rt][i].c;
if(!op)trie.update(x,c);
else ans[c]=max(ans[c],trie.query(x));
}
if(l==r)return;
int mid=(l+r)/2;
getans(l,mid,rt*2);
getans(mid+1,r,rt*2+1);
}
}tree;
int in[maxx],out[maxx],cnt;
void dfs(int u,int fa)
{
in[u]=++cnt;
for(int i=0;i<ma[u].size();i++)
{
int v=ma[u][i];
if(v==fa)continue;
dfs(v,u);
}
out[u]=cnt;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)ma[i].clear();
int x;
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
ma[x].push_back(i);
ma[i].push_back(x);
}
cnt=0;
dfs(1,0);
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
trie.init();
tree.build(1,n,1);
for(int i=1;i<=n;i++)
tree.update(1,n,in[i],out[i],w[i],1,1);
int op,y,q=0;
while(m--)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%d",&x,&y);
tree.update(1,n,in[x],out[x],w[x],-1,1);
w[x]=y;
tree.update(1,n,in[x],out[x],w[x],1,1);
}
else
{
scanf("%d",&x);
ans[++q]=0;
tree.query(1,n,in[x],w[x],q,1);
}
}
tree.getans(1,n,1);
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
}
return 0;
}