題意:
有一棵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 從下往上更新.由於每一次維護只維護四個點的值,且每次在每一棵樹上也只會修改一條鏈的值.每次...