COJ 0970 WZJ的資料結構(負三十)樹分治

2022-05-23 02:33:11 字數 4542 閱讀 2824

wzj的資料結構(負三十)

難度級別:d; 執行時間限制:1000ms; 執行空間限制:262144kb; **長度限制:2000000b

試題描述

給你一棵n個點的無根樹,點和邊上均有權值。請你設計乙個資料結構,回答m次操作。

1 x v:對於樹上的每乙個節點y,如果將x、y在樹上的距離記為d,那麼將y節點的權值加上d*v。

2 x:詢問節點x的權值。

輸入第一行為乙個正整數n。

第二行到第n行每行三個正整數ui,vi,wi。表示一條樹邊從ui到vi,距離為wi。

第n+1行為乙個正整數m。

最後m行每行三個或兩個正整數,格式見題面。

輸出對於每個詢問操作,輸出答案。

輸入示例

101 2 2

1 3 1

1 4 3

1 5 2

4 6 2

4 7 1

6 8 1

7 9 2

7 10 1

91 3 1

1 10 1

2 12 4

2 51 5 1

1 8 1

2 22 9

輸出示例66

1022

24其他說明

對於30%的資料:1<=n,m<=1000

另有50%的資料:1<=n,m<=100000,保證修改操作均在詢問操作之前。

對於100%的資料:1<=n,m<=100000,1<=x<=n,1<=v,wi<=1000

題解:先想用點分治弄離線分數:首先轉化問題,轉換查詢和修改的物件;然後窩萌變形一下查詢所求,dist(x,y)*a[x]=(dep[x]+dep[y])*a[x]=dep[x]*a[x]+dep[y]*a[x];然後窩萌就是要求出dep[x]*a[x]和a[x],這個掃兩遍就好了。。。

1 #include2 #include3 #include4 #include5 #include6 #include7

#define pau putchar(' ')

8#define ent putchar('\n')

9using

namespace

std;

10const

int maxn=100000+10,maxm=200000+10,inf=-1u>>1;11

int n,q,a[maxn],cg,f[maxn],siz[maxn],size;bool

vis[maxn];

12struct tedadj[maxm],*fch[maxn],*ms=adj;

13void add(int x,int y,int

w);fch[x]=ms++;

15 *ms=(ted);fch[y]=ms++;

16return;17

}18long

long

ans[maxn],sum,sumd,tsum,tsumd;

19void findcg(int x,int

fa)25 }f[x]=max(mxs,size-siz[x]);if(f[x]return;26

}27void dfs(int x,int fa,int

dis)

34 }return;35

}36void solve(int x=cg)ans[x]+=sum;sum=0;sumd=0;44

while(top--)

47for(ted*e=fch[x];e;e=e->nxt)

51 }return;52

}53 inline int

read()

56while(isdigit(ch))x=10*x+ch-'

0',ch=getchar();

57return x*=sig;58}

59 inline void write(int

x)if(x<0)putchar('

-'),x=-x;

61int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;62

for(int i=len-1;i>=0;i--)putchar(buf[i]+'

0');return;63

}64void

init()

69int

qs[maxn],m;

70void

work()

77 f[cg=0]=size=n;findcg(1,0

);solve();

78for(int i=1;i<=m;i++)printf("

%lld\n

",ans[qs[i]]);

79return;80

}81void

print()

84int main()

85/*

8610

871 2 2

881 3 1

891 4 3

901 5 2

914 6 2

924 7 1

936 8 1

947 9 2

957 10 1966

971 3 1

981 10 1

991 5 1

1001 8 1

1012 2

1022 9

103*/

動態樹做法:%%%小健健,動態樹分治其實就是把重心累成一棵樹,這棵樹保證了樹高logn。窩萌把資訊分三份累加在覆蓋這個操作點的最多logn個重心上,分別是整棵子樹的資訊all,本子樹到重心的父親的距離資訊cha &#%&!。。。(意會意會。。。),本子樹到重心的距離資訊tre @*%&#¥%……。。。(意會意會。。。)

有幾個tips!

1.窩萌的一切操作都是在重心樹上進行的!

2.tre,cha,all這些變數名稱好眼熟?(。。。aaa樹!。。。逃。。。

3.相當好寫!壓倒性優勢勝過點分治有木有!

4.為了保持複雜度,詢問兩點距離這裡採用了lca轉rmq,做到了o(nlogn)-o(1)

1 #include2 #include3 #include4 #include5 #include6 #include7

#define pau putchar(' ')

8#define ent putchar('\n')

9using

namespace

std;

10const

int maxn=100000+10,maxm=200000+10,inf=-1u>>1;11

struct tedadj[maxm],*fch[maxn],*ms=adj;

12void add(int x,int y,int

w);fch[x]=ms++;

14 *ms=(ted);fch[y]=ms++;

15return;16

}17int siz[maxn],cg,size,f[maxn],dep[maxn],mi[maxm][20

],log[maxm],cnt,pos[maxn],fa[maxn];

18bool vis[maxn];long

long

all[maxn],cha[maxn],tre[maxn];

19void dfs(int x,int

fa)25 }return;26

}27void

initrmq()

33int dist(int x,int

y)37

void findcg(int x,int

fa)43 }f[x]=max(mxs,size-siz[x]);if(f[x]return;44

}45void solve(int x=cg)

51 }return;52

}53void update(int x,int

v)return;59

}60long

long query(int

x)return

ans;66}

67 inline int

read()

73 inline void write(long

long

x)if(x<0)putchar('

-'),x=-x;

75int len=0;long

long buf[20];while(x)buf[len++]=x%10,x/=10;76

for(int i=len-1;i>=0;i--)putchar(buf[i]+'

0');return;77

}78intn,q;

79void

init()

88return;89

}90void

work()

93void

print()

96int main()

97/*987

991 5 4

1001 2 5

1011 3 1

1023 6 2

1033 4 6

1044 7 2

1051 6

106*/

COJ1013 WZJ的資料結構(十三)

這道題有這樣乙個解法 首先把邊依次加到圖中,若當前這條邊與圖中的邊形成了環,那麼把這個環中最早加進來的邊彈出去 並將每條邊把哪條邊彈了出去記錄下來 ntr i j,特別地,要是沒有彈出邊,ntr i 0 這個顯然是可以用lct來弄的對吧。然後對於每個詢問,我們的答案就是對l r中ntr小於l的邊求和...

COJ0985 WZJ的資料結構(負十五)

coj0985 wzj的資料結構 負十五 試題描述 chx有乙個問題想問問大家。給你乙個長度為n的數列a,請你找到兩個位置l,r,使得a l a l 1 a r 中沒有重複的數,輸出r l 1的最大值。以上是附中聯賽加試的一道題。wzj覺得這道題太水了,改了改題目 wzj有乙個問題想問問大家。給你乙...

COJ0989 WZJ的資料結構(負十一)

coj0989 wzj的資料結構 負十一 試題描述 給出以下定義 1.若子串行 l,r 的極差 最大值 最小值 m,則子串行 l,r 為乙個均勻序列。2.均勻序列 l,r 的權值為sum l,r 即序列的元素和。現在給你乙個長度為n的整數序列a,請你求出權值前k大的均勻序列,輸出k行為它們的權值。輸...