Vani有約會 雨天的尾巴

2022-05-19 02:55:08 字數 1848 閱讀 1609

題意:

有一棵n個點的樹,m次操作,每次操作給路徑$(u,v)$上每個點發乙個型別為w的物品。

在所有操作後請你求出每個點個數最多的物品型別。

$n,m,w\leq 10^$。

題解:樹鏈剖分基本就是把序列問題上樹,於是考慮序列怎麼做,直接把區間加改成差分再維護一棵權值線段樹即可。

複雜度$o(n\log^)$。注意那個w不一定小於n,這個玩意差點把我坑死。

套路:**:

#include#define maxn 1000005

#define maxm 500005

#define inf 0x7fffffff

#define ll long long

#define rint register int

#define debug(x) cerr<

namespace

std;

inttop[maxn],e[maxn],id[maxn],rt[maxn];

int to[maxn<<1],nxt[maxn<<1

],hd[maxn],cnt;

intf[maxn],dep[maxn],siz[maxn],son[maxn];

int tr[maxn<<2],mx[maxn<<2

],ans[maxn];

vector

vc[maxn];

inline

intread()

inline

void addedge(int u,int

v)inline

void dfs1(int u,int

fa)}

inline

void dfs2(int u,int

tp)}

inline

void solve(int u,int v,int

w)

if(dep[u]>dep[v]) swap(u,v);

int st=id[u],ed=id[v];

vc[st].push_back(w),vc[ed+1].push_back(-w);

}inline

void add(int x,int y,int l,int r,int

k)

int mid=l+r>>1

;

if(x<=mid) add(x,y,l,mid,k<<1

);

else add(x,y,mid+1,r,k<<1|1

);

if(tr[k<<1]>=tr[k<<1|1]) tr[k]=tr[k<<1],mx[k]=mx[k<<1

];

else tr[k]=tr[k<<1|1],mx[k]=mx[k<<1|1];}

inline

void build(int l,int r,int

k)

int mid=l+r>>1

; build(l,mid,k

<<1

); build(mid+1,r,k<<1|1);}

intmain()

dfs1(

1,0),dfs2(1,1

);

for(int i=1;i<=m;i++)

build(

1,100000,1

);

for(int i=1;i<=n;i++)

ans[e[i]]=(tr[1]==0)?0:mx[1

]; }

for(int i=1;i<=n;i++)

cout

return0;

}

樹剖寫法

Vani有約會 雨天的尾巴

我之前考試是遇到過這題,但是資料範圍k 20,狀壓就能過。結果原題範圍k 100000 果斷線段樹合併。比如兩個相同大小的線段樹,將b樹各個區間上的值合併到a樹上,從樹根開始合併,然後遞迴合併左右兒子,有三種情況 假設現在a樹遍歷到x點,b樹遍歷到y點 1.x,y至少其一未被修改過 語文不好勿噴 則...

P4556 Vani有約會 雨天的尾巴

目錄每個節點維護一課線段樹 當然是動態開點 線段樹的作用是統計這個節點有多少種糧食型號,以及最多的糧食型號 然後樹上差分,u和v點 1,lca u,v 和f lca u,v 1 不顯然就畫圖嘍 並不用轉化為dfs序 只需要dfs一邊,自底向上合併就好 刪除節點不必建樹 因為在遞迴到他的時候一定是存在...

Vani有約會 雨天的尾巴 線段樹合併

樹上差分 線段樹合併.在每個節點上維護一棵權值線段樹.然後如果需要修改 x,y 兩點,則在 x 處和 y 處分別加上 1 的權值.然後在 lca x,y 以及 fa lca x,y 處減掉 1 最後面 dfs 從下往上更新.由於每一次維護只維護四個點的值,且每次在每一棵樹上也只會修改一條鏈的值.每次...