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

2022-04-30 09:18:06 字數 1395 閱讀 7417

樹上差分+線段樹合併.

在每個節點上維護一棵權值線段樹.

然後如果需要修改 \(x,y\) 兩點,則在 \(x\) 處和 \(y\) 處分別加上 \(1\) 的權值.

然後在 \(lca(x,y)\) 以及 \(fa[lca(x,y)]\) 處減掉 \(1\) .

最後面 \(dfs\) 從下往上更新.

由於每一次維護只維護四個點的值,且每次在每一棵樹上也只會修改一條鏈的值.

每次操作時間複雜度和空間複雜度均為 \(o(4*logn)\) .

所以整體時間和空間複雜度即為 \(o(4*nlogn)\) .可以過.

#include#define n 100008

#define in(x) x=read()

using namespace std;

struct sja[n*2];

int head[n*2],size,n,q;

int dep[n*2],fa[n*2][20],v[n*2];

int t[n*2],l[n*60],r[n*60],rans[n*2];

int num[n*60],rt,tot,m,ans[n*60],ans[n*60];

int read()

while(ch>='0'&&ch<='9')

return f*w;

}void add(int x,int y)

void dfs(int x,int fr)

}int lca(int x,int y)

void pushup(int node)

void update(int &node,int l,int r,int pos,int v)

int mid=(l+r)/2;

if(pos<=mid) update(l[node],l,mid,pos,v);

else update(r[node],mid+1,r,pos,v);

if(l!=r)

pushup(node);

}int merge(int x,int y,int l,int r)

void dfs(int x,int fr)

if(ans[t[x]]>0)

rans[x]=ans[t[x]];

}int main()

dep[1]=1; dfs(1,0);

for(int j=1;j<=19;j++)

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

fa[i][j]=fa[fa[i][j-1]][j-1];

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

dfs(1,0);

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

printf("%d\n",rans[i]);

}

Vani有約會 雨天的尾巴

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

Vani有約會 雨天的尾巴

題意 有一棵n個點的樹,m次操作,每次操作給路徑 u,v 上每個點發乙個型別為w的物品。在所有操作後請你求出每個點個數最多的物品型別。n,m,w leq 10 題解 樹鏈剖分基本就是把序列問題上樹,於是考慮序列怎麼做,直接把區間加改成差分再維護一棵權值線段樹即可。複雜度 o n log 注意那個w不...

P4556 Vani有約會 雨天的尾巴

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