問題の説明
多くの労力を費やし、ベンCJK神は最終的に最初の3つのタイトルを完了しました。「はい、神はああ確かに新世代のベンです!」JesseLiuは、満足して言った、「しかし、あなた算数における技能のデータ構造を使用するため、すべての非常によくある、あなたは何をするかを把握する必要がありますか?」
「データ構造を、」聞く言葉は、神CJKベンは助けるが、冷や汗ができなくてもよう。「若い人、今、私のために、ツリー与えられた、あなたは次の操作を行う必要があります。
1点の重みを変更し、
2点の値の間のパス上のすべてのポイントを照会する2.右;
3.クエリを。木の右のアイデアや価値観「
軽蔑のCJK面フラッシュ:?それは裸の断面タイトルトラックのチェーンではありません
。」これはちょうど最初の質問である「JesseLiuこの質問はあまりにも多くの水を考えているようだし、コメントを追加しました:」完了上記の操作のすべての後、私は次のことを依頼する必要があります。
- kに等しい未満どのように多くの木々右ポイントの考えを尋ねました。
- 重量がより小さいか等しいkとどのくらいの点の2点間の経路について尋ね、 "
ベンCJKは神であるが、このような問題が発生したが、助けることが少し恐怖を感じることができません。幸いなことに、自分の形而上学的な力によって、彼は彼のクラスメートに連絡を - あなた。今、私たちは、水のうちに、この最後の質問をお願いします。
入力形式
数nの最初のライン、ポイントの合計数。次に、N-1行、行二つの整数xとyは、xとyとの間に接続されたエッジを表現しました。次に、整数m1は、Qは、最初の操作の数を表します。次に、動作はラインM1、次の形式で表される:
「XY 1」の重みがX yを指すように変更され;
(XおよびYを含む)経路上の点xとyの右側にある「2 XY」クエリ
「×3」及び(Xを含む)右点は、サブツリークエリをX;
次のラインM2、Qは、第二の操作の数を表しています。:次に、動作は次の形式でM2の行、記載されている
「XYZ 1」パス上のX yを依頼する点の数はZより小さいか等しい重みである。
「2 XY」量よりも小さくなっているどのように多くの点xのサブツリーを掲載これはYに等しく、
各点の初期量は0です。
出力フォーマット
各お問い合わせは、出力は、クエリに対する整数の答えを表します。
サンプル入力と出力
サンプル入力1
3
1 2
1 3
3
1 1 3
1 3 1
3 1
2
2 1 2
1 1 3 1
サンプル出力1
4
2
1
サンプル入力2
5
1 2
1 3
3 4
3 5
5
3 1
1 3 1
2 4 5
1 4 -1
3 3
2
1 0 5
2 3 -1
解決
最初の質問については、明らかにチェーンツリーは、クエリの単一のポイントを分割し、間隔プラス裸のタイトルを変更し、あなたが直接行うことができます。
2番目の質問のために、ポイント1に寄与し、その結果、ポイントは、クエリ(またはサブツリーパス)の範囲内である場合にのみ、寄与を生成します。制約を満たすために、我々は尋ねられたとき、ノード内の残りのノードの値以上に加えて以下にインタロゲーション値がゼロであることを確認する必要があり。私たちが考えることができる、あなたは大規模な注文に小さな値について質問やお問い合わせを最初の重量に応じて、一緒に一つの動作ノード配列に覚えておくことが求められます。動作値に対応するノードとして各ノードは尋ね最初の質問で、1となります。
コード
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 500002
using namespace std;
struct opt{
int op,id,x,y,val;
}a[N];
int head[N],ver[N*2],nxt[N*2],l;
int n,m1,m2,i,dfn[N],end[N],tim,ans[N];
int fa[N],size[N],top[N],son[N],dep[N],pos[N],tree[N],cnt;
void insert(int x,int y)
{
l++;
ver[l]=y;
nxt[l]=head[x];
head[x]=l;
}
void dfs1(int x)
{
size[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=fa[x]){
fa[y]=x;
dep[y]=dep[x]+1;
dfs1(y);
if(size[son[x]]<size[y]) son[x]=y;
size[x]+=size[y];
}
}
}
void dfs2(int x,int tp)
{
dfn[x]=++tim;
pos[x]=++cnt;top[x]=tp;
if(son[x]) dfs2(son[x],top[x]);
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(y!=son[x]&&y!=fa[x]) dfs2(y,y);
}
end[x]=tim;
}
void update(int p,int l,int r,int x,int val)
{
if(x<l||r<x) return;
if(l==r){
tree[p]=val;
return;
}
int mid=(l+r)/2;
update(p*2,l,mid,x,val);
update(p*2+1,mid+1,r,x,val);
tree[p]=tree[p*2]+tree[p*2+1];
}
int ask(int p,int l,int r,int ql,int qr)
{
if(r<ql||l>qr) return 0;
if(l>=ql&&r<=qr) return tree[p];
int mid=(l+r)/2;
return ask(p*2,l,mid,ql,qr)+ask(p*2+1,mid+1,r,ql,qr);
}
int find(int u,int v)
{
int f1=top[u],f2=top[v],ans=0;
while(f1!=f2){
if(dep[f1]<dep[f2]) swap(f1,f2),swap(u,v);
ans+=ask(1,1,n,pos[f1],pos[u]);
u=fa[f1];f1=top[u];
}
if(dep[u]>dep[v]) swap(u,v);
return ans+ask(1,1,n,pos[u],pos[v]);
}
int my_comp(const opt &a,const opt &b)
{
if(a.val==b.val) return a.op<b.op;
return a.val<b.val;
}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
cin>>n;
for(i=1;i<n;i++){
int u,v;
cin>>u>>v;
insert(u,v);
insert(v,u);
}
dfs1(1);
dfs2(1,1);
cin>>m1;
for(i=1;i<=m1;i++){
int op,x,y;
cin>>op;
if(op==1){
cin>>x>>y;
update(1,1,n,pos[x],y);
}
else if(op==2){
cin>>x>>y;
cout<<find(x,y)<<endl;
}
else{
cin>>x;
cout<<ask(1,1,n,dfn[x],end[x])<<endl;
}
}
cin>>m2;
int tmp=m2;
for(i=1;i<=m2;i++){
int op,x,y,z;
cin>>op;
if(op==1){
cin>>x>>y>>z;
a[i]=(opt){op,i,x,y,z};
}
else{
cin>>x>>y;
a[i]=(opt){op,i,x,0,y};
}
}
for(i=1;i<=n;i++) a[++m2]=(opt){0,m2,i,0,ask(1,1,n,pos[i],pos[i])};
memset(tree,0,sizeof(tree));
sort(a+1,a+m2+1,my_comp);
for(i=1;i<=m2;i++){
if(a[i].op==0) update(1,1,n,pos[a[i].x],1);
else if(a[i].op==1) ans[a[i].id]=find(a[i].x,a[i].y);
else ans[a[i].id]=ask(1,1,n,dfn[a[i].x],end[a[i].x]);
}
for(i=1;i<=tmp;i++) cout<<ans[i]<<endl;
fclose(stdin);
fclose(stdout);
return 0;
}
概要
ひとつのアイデア:影響を排除するためには、尋問の後、および実装適切な変換を注文して影響を与えることができます。