time limit: 200 sec memory limit: 512 mb
submit: 1438 solved: 749
[submit][status][discuss]
sample input
84131
2784
分析:沒想到這能用莫隊來做......
先看資料,10w,應該是nlogn的演算法?時限有200s,nsqrt(n)應該也可以. 於是開始想根號演算法.
樹上的根號演算法?先把問題化簡一下:如果沒有修改操作並且是在序列上操作.
化簡後的題目就非常好做了,莫隊裸題.維護乙個桶即可.
有修改操作該怎麼辦呢? 帶修改的莫隊就好了嘛,詳情可見:bzoj2120.
在樹上怎麼辦呢? 樹上的帶修改的莫隊?這是個什麼東西......實際上確實有這種演算法.
首先要像普通莫隊演算法一樣給樹分塊,至於怎麼給樹分塊?可見:bzoj1086.
然後就和普通莫隊演算法差不多啦,維護兩個指標l和r,乙個陣列vis表示i這個點有沒有被計入答案中. 如果(l,r) 轉移到 (l',r'),第一想法肯定是將路徑(l,l')和路徑(r,r')上的點的vis全部取反,然後更新答案. 這樣會有乙個問題:如果一開始l,r在l',r'的lca處,那麼這樣lca會被取反兩次,沒有被統計進入答案. 這是因為兩條路徑在lca處可能會重疊!
怎麼辦呢?先不考慮lca就好了. (l,r)轉移到(l',r'),將路徑(l,l')和路徑(r,r')上的點除了l和l'的lca 以及 r和r'的lca都取反. 在草稿紙上畫幾個例子就能發現,這個方法統計的答案一定不會包含當前(l,r)的lca,但是包含路徑上其它的所有點. 最後單獨算一下lca的貢獻就好了.
注意點:先單獨處理第乙個詢問以及在它之前的修改. 這一步是直接從(l,l)轉移到(r,r). 在dfs時要維護dfs序,如果查詢的l的dfs序>r的dfs序,則交換l,r.
總結一下樹上帶修改的莫隊吧:
1.先對樹進行分塊.
2.對查詢陣列進行排序.
3.單獨處理第乙個詢問以及之前的修改.
4.先移動time指標,再直接從(l,r)轉移到(l',r'),分別對應上一次詢問的l,r和這一次詢問的l,r.
如何修改?
單點修改:如果vis[x] == 0,否則先把消掉x原本的顏色,再換顏色,統計貢獻.
路徑修改:每次把深度大的往上跳,單點修改.直到兩個點重合.
每次修改完路徑後要修改lca,統計答案後還原lca.
#include #include#include
#include
#include
using
namespace
std;
const
int maxn = 200010
;int n,m,q,head[maxn],to[maxn],nextt[maxn],tot = 1,w[maxn],v[maxn],fa[maxn][20
];int deep[maxn],belong[maxn],ecnt = 0
,c[maxn],block,top,sta[maxn],last[maxn];
intcnt1,cnt2,col[maxn],tong[maxn],vis[maxn],pos[maxn],dfs_clock;
long
long
ans,anss[maxn];
struct
node1
q[maxn];
struct
node2
md[maxn];
void add(int x,int
y)int dfs(int u,int
faa)}}
sta[++top] =u;
return left + 1;}
bool
cmp(node1 a,node1 b)
int lca(int x,int
y)
return fa[x][0];}
void update3(int
x)
else
}void update1(int x,intv)}
void update2(int x,int
y)
else
}}void
solve()
while (time >q[i].tim)
update2(q[i - 1
].l,q[i].l);
update2(q[i - 1
].r,q[i].r);
lca =lca(q[i].l,q[i].r);
update3(lca);
anss[q[i].id] =ans;
update3(lca);
}}int
main()
dfs(
1,0);
++ecnt;
while
(top)
belong[sta[top--]] =ecnt;
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 <= n; i++)
for (int i = 1; i <= q; i++)
else
}sort(q + 1,q + 1 +cnt2,cmp);
solve();
for (int i = 1; i <= cnt2; i++)
printf(
"%lld\n
",anss[i]);
return0;
}
BZOJ 3052 wc2013 糖果公園
蒟蒻去做糖果公園了qaq 講道理速度能排rk11很開心啊 其實前人之述備矣 複雜度分析 推薦一波棟爺爺的題解 帶修改莫隊其實就是多一維時間 所以你需要資瓷修改和撤銷修改 然後就跟沒修改的莫隊其實差不多了 關於樹上莫隊 很明顯就是用dfs序這個套路 發現出現次數為奇數次的才會算到 棟老師題解那裡也有說...
BZOJ 3052 wc2013 糖果公園
讀題很容易知道這就是一道簡單的樹上帶修改莫隊,樹上待修改莫隊只要將待修改莫隊和樹上莫隊結合起來使用就可以了。感謝darkbzoj include include include include include include include include set include include i...
BZOJ 3052 WC 2013 糖果公園
對樹的dfs序分塊,開啟了新世界的大門233 第一關鍵字是l所在的塊,第二關鍵字是r所在的塊,第三關鍵字是時間,分完塊後暴力莫隊即可 include include include includeusing namespace std typedef long long ll const int n...