删边转化为加边

然后每次用线段树合并就行.....

确确实实很简单

然而为什么线段树合并跑不过$splay$的启发式合并,常数稍大了点...

复杂度$O(n \log n)$

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
namespace remoon {
#define ri register int
#define ll long long
#define tpr template <typename ra>
#define rep(iu, st, ed) for(ri iu = st; iu <= ed; iu ++)
#define drep(iu, ed, st) for(ri iu = ed; iu >= st; iu --)
#define gc getchar
inline int read() {
int p = , w = ; char c = gc();
while(c > '' || c < '') { if(c == '-') w = -; c = gc(); }
while(c >= '' && c <= '') p = p * + c - '', c = gc();
return p * w;
}
int wr[], rw;
#define pc(iw) putchar(iw)
tpr inline void write(ra o, char c = '\n') {
if(!o) pc('');
if(o < ) o = -o, pc('-');
while(o) wr[++ rw] = o % , o /= ;
while(rw) pc(wr[rw --] + '');
pc(c);
}
}
using namespace std;
using namespace remoon; #define sid 200050
#define pid 5000500 ll ans;
ll sum[sid];
int n, id, cnp;
int x[sid], y[sid], p[sid];
int cap[sid], nxt[sid], node[sid], val[sid], s[sid];
int fa[sid], rt[sid], ls[pid], rs[pid], sz[pid]; inline void addedge(int u, int v, int w) {
nxt[++ cnp] = cap[u]; cap[u] = cnp;
node[cnp] = v; val[cnp] = w;
nxt[++ cnp] = cap[v]; cap[v] = cnp;
node[cnp] = u; val[cnp] = w;
} inline int find(int o) {
if(fa[o] == o) return o;
return fa[o] = find(fa[o]);
} inline void insert(int &now, int l, int r, int v) {
now = ++ id; sz[now] = ;
if(l == r) return;
int mid = (l + r) >> ;
if(v <= mid) insert(ls[now], l, mid, v);
else insert(rs[now], mid + , r, v);
} inline int merge(int x, int y, int l = , int r = << ) {
if(!x || !y) return x + y;
if(l == r) ans += 1ll * sz[x] * sz[y];
int mid = (l + r) >> ;
ls[x] = merge(ls[x], ls[y], l, mid);
rs[x] = merge(rs[x], rs[y], mid + , r);
sz[x] += sz[y];
return x;
} #define cur node[i]
inline void dfs(int o, int f) {
insert(rt[o], , << , s[o]);
for(int i = cap[o]; i; i = nxt[i])
if(cur != f) s[cur] = s[o] ^ val[i], dfs(cur, o);
} int main() {
n = read();
rep(i, , n - ) {
x[i] = read(); y[i] = read();
int w = read(); addedge(x[i], y[i], w);
}
rep(i, , n) fa[i] = i;
rep(i, , n - ) p[i] = read();
dfs(, );
drep(i, n - , ) {
int u = find(x[p[i]]), v = find(y[p[i]]);
fa[v] = u; merge(rt[u], rt[v]);
sum[i] = ans;
}
rep(i, , n) write(sum[i]);
return ;
}

最新文章

  1. 纸箱堆叠 bzoj 2253
  2. 在ubuntu 14.04 64位添加32位库
  3. java-HashMap方法讲解
  4. error: Refusing to undefine while domain managed save image exists
  5. Noip2014 提高组 T2 联合权值 连通图+技巧
  6. Unity 随机数的使用
  7. 如何阅读mysql源码
  8. eclipse 中执行 main 函数如何添加参数
  9. C#开发微信门户及应用(48) - 在微信框架中整合CacheManager 缓存框架
  10. C 语言 计算
  11. 【codevs4919】线段树练习4
  12. [原]openstack-kilo--issue(十二)openstack-keystone和httpd服务同时占用35357和5000
  13. C#学习入门第二篇
  14. 性能测试-10.数据分析Analysis
  15. Linux下查看编辑二进制文件:hexedit神器
  16. 打包jar问题
  17. 转载:30多条mysql数据库优化方法,千万级数据库记录查询轻松解决
  18. Flex与SSH集成
  19. 【Apache】ab工具
  20. 2018 计算之道初赛第二场 阿里巴巴的手机代理商(困难)(反向可持久化Trie)

热门文章

  1. 【方法】纯jQuery实现星巴克官网导航栏效果
  2. APScheduler API -- apscheduler.triggers.date
  3. Linux/Unix系统编程手册 第一章:历史和标准
  4. python端口扫描
  5. 利用反射型XSS二次注入绕过CSP form-action限制
  6. nginx配置浅析
  7. iptables详细设置
  8. C# 去除文件非法字符名
  9. yum怎么用?
  10. 树莓派指定静态IP