P4556 Vani有約會 雨天的尾巴

2022-03-01 05:12:28 字數 1911 閱讀 7685

目錄每個節點維護一課線段樹(當然是動態開點)

線段樹的作用是統計這個節點有多少種糧食型號,以及最多的糧食型號

然後樹上差分,u和v點 +1,lca(u,v)和f[lca(u,v)] -1(不顯然就畫圖嘍)

並不用轉化為dfs序

只需要dfs一邊,自底向上合併就好

刪除節點不必建樹

因為在遞迴到他的時候一定是存在的

(要不 他還能減成負數嗎、、)

但在一開始建樹的時候就不一定存在了

所以記錄下來就好

這合併真的靠譜嗎

如果兩個線段樹都是滿二叉那不涼涼了

先引用部落格大佬一段:

這樣子做時間複雜度取決於重合節點個數

因為滿二叉樹的結點數是o(n)

對每個結點進行處理是o(logn)

最壞複雜度是o(nlogn),

看著很涼,但是一點也不涼(說出了什麼b話)

假設乙個為滿二叉

最壞複雜度的情況一定是重合部分最多的時候

也就是每條鏈都是分開的(一條鍊子合併複雜度最壞為logn)

一次修改4個點,一共修改4n個點 (n,m同階的話)

那複雜度就是4nlogn也就是nlogn了

平均每棵樹4點,實際上也不會每次修改logn

emma,應該是這樣

n並不是救濟糧型號的範圍

所以建樹應該是1到10w而不是n

zz了,2333

//¢¢£

#include #define for(i,a,b) for(int i=a;i<=b;++i)

using namespace std;

const int maxn=1e5+7;

const int n=1e5;

inline int read()

int n,m,ans[maxn],cnt,rt[maxn];

vectordelet[maxn];

int ch[maxn*50][2],ma[maxn*50],id[maxn*50];

//關於圖

struct edge e[maxn<<1];

int head[maxn<<1],tot;

void add_edge(int u,int v)

namespace lca

} int lca(int x,int y)

void init()

}void pushup(int now)

void build(int &now,int l,int r,int k,int up)

int mid=(l+r)>>1;

if(k<=mid) build(ch[now][0],l,mid,k,up);

else build(ch[now][1],mid+1,r,k,up);

pushup(now);

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

int mid=(l+r)>>1;

ch[x][0]=merge(l,mid,ch[x][0],ch[y][0]);

ch[x][1]=merge(mid+1,r,ch[x][1],ch[y][1]);

pushup(x);

return x;

}void dfs(int u,int f)

for(vector::iterator it=delet[u].begin();it!=delet[u].end();++it)

build(rt[u],1,n,*it,-1);

ans[u]=id[rt[u]];

}int main()

lca::init();

for(i,1,m)

dfs(1,0);

for(i,1,n) cout

}

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不...

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

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