這題絕對好題。
題意很簡單,也很容易想到樹鏈剖分,之後就不太好做了。
開始想的是按顏色排序,然後每次處理一種顏色,求出最優解。這樣做的話,最壞情況會退化到n^2,不可接受。
之後用線段樹維護,乙個節點只存在一種顏色,而且排序之後能保證在樹中顏色不會交叉,pushdown的時候可以將兩種都不是當前正在處理的顏色給覆蓋掉,不過這樣寫有個bug一直沒解決掉,就是如果更新一直在葉子節點,如何確定該不該覆蓋存在問題,這種寫法又掛掉了。
這題做完之後,剖分之後的樹在腦中再也不是樹,是鏈。
具體看**:
#pragma comment(linker,"/stack:102400000,102400000")
#include #include #include #include #include #define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf int m=(l+r)>>1
using namespace std;
const int max=100010;
int top[max];
int num[max];
int son[max];
int fa[max];
int dep[max];
int pos[max]; //原樹->新鏈
int cpos[max]; //新鏈->原樹
int cn[max<<2]; //每個節點當前種子型別的種子數
int cz[max<<2]; //每個節點當前種子型別
int ans[max]; //答案
int head[max];
vector mv[max]; //每個節點的標記
int n,m,curz,cnt,sss;
struct edge
edge[max<<1];
struct path
path[max];
void init() //初始化
cnt=0;
sss=1;
return ;
}void add_edge(int a,int b,int i) //建樹
void dfs1(int u,int d,int f)
next=edge[next].next;
}return ;
}void dfs2(int u,int t)
return ;
}//剖分結束
//線段樹維護的是每種顏色的數量,cz代表顏色,cn代表數量
void swap(int &a,int &b)
void pushup(int rt)
else
return ;
}void build(int l,int r,int rt)
void update(int k,int v,int l,int r,int rt)
delf;
if (k<=m)
update(k,v,lson);
else
update(k,v,rson);
pushup(rt);
return ;
}//線段樹結束
//標記首尾節點部分
void solve(int x,int y,int z)
ans[cpos[i]]=cz[1]; //當前點維護結束之後,根節點的就是答案
}return ;
}int main()
{ while (scanf("%d%d",&n,&m)&&n+m)
{init();
for (int i=1;i
hdu 5029 樹鏈剖分 鍊錶
因為是塗色問題,可以採用標記l 處 和r 處 1,把樹狀結構通過樹鏈剖分轉換成線性,利用線段樹維護顏色中出現的最多的,利用二分查詢能夠找到出現次數最多且序號最小的顏色 include include include include define max 200007 using namespace ...
HDU 5029 樹鏈剖分 權值線段樹
題目鏈結 題意 給定一顆n個結點的樹,進行m次染色操作,對於每一次染色操作是選擇樹上的一條路徑,將路徑上所有節點都染上第z zz種顏色。輸出m次操作以後,每乙個節點上染色次數最多的顏色。1 n m,z 1 e5 1 n,m,z 1e5 1 n m,z 1 e5思路 對於樹上的路徑操作,自然能夠想到使...
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...