题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5893
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 603 Accepted Submission(s): 154
思路:与HYSBZ 2243 [SDOI2011]染色这一题几乎完全一样,都是树链剖分和线段树的组合应用题。只不过这里将点权操作变成了边权操作,处理起来稍微麻烦一点。在比赛时,一下子就想到了染色这一题,但是因为没有A掉,所以不会改。哎!自己太弱了啊!难点在于链的拼接。在进行链的合并时,判断两个链的端点是否一致,一致的话答案减少一,否则不减少。注意:询问时,两点相同答案为0,但数据可能不存在这种情况,所以不判断也能A掉。详见代码。
附上AC代码:
#include
#define lrt rt<<1
#define rrt rt<<1|1
#define lson l, m, lrt
#define rson m+1, r, rrt
using namespace std;
const int maxn = 40005;
// 分别表示以当前节点作为根的子树的节点数目,
// 树上各个节点的初始值,当前节点的重儿子
int sizev[maxn], num[maxn], son[maxn];
// 分别表示树链上深度最小的节点,当前节点的深度,
// 原节点在剖分后的时间戳,即新的编号
int top[maxn], deep[maxn], pos[maxn];
// 分别表示当前时间戳对应的原节点编号,
// 当前节点的父节点
int level[maxn], p[maxn];
// 判断该节点是否被访问过了
bool vis[maxn];
// 分别表示节点数,询问数和时间戳计数
int n, q, cnt;
// 存储树的各个节点所连接的边
vector edge[maxn];
void init(){
for (int i=1; i<=n; ++i){
sizev[i] = top[i] = son[i] = 0;
deep[i] = pos[i] = level[i] = 0;
p[i]=0, vis[i]=false;
cnt = 0;
edge[i].clear();
}
}
void add_edge(int u, int v){
edge[u].push_back(v);
edge[v].push_back(u);
}
void dfs1(int u, int root){
vis[u] = true;
sizev[u] = 1;
p[u] = root;
deep[u] = deep[root]+1;
int siz = edge[u].size();
for (int i=0; i>1;
build(lson);
build(rson);
push_up(rt);
}
void push_down(int l, int r, int rt){
if (setv[rt] != -1){
setv[lrt] = setv[rrt] = setv[rt];
sumv[lrt] = sumv[rrt] = 1;
lv[lrt] = lv[rrt] = setv[rt];
rv[lrt] = rv[rrt] = setv[rt];
setv[rt] = -1;
}
}
void update(int cl, int cr, int val, int l, int r, int rt){
if (cl<=l && r<=cr){
setv[rt] = lv[rt] = rv[rt] = val;
sumv[rt] = 1;
return ;
}
push_down(l, r, rt);
int m = (l+r)>>1;
if (cl <= m)
update(cl, cr, val, lson);
if (cr > m)
update(cl, cr, val, rson);
push_up(rt);
}
int queries(int ql, int qr, int l, int r, int rt){
if (ql<=l && r<=qr)
return sumv[rt];
push_down(l, r, rt);
int m = (l+r)>>1;
int sumr = 0;
if (ql <= m)
sumr += queries(ql, qr, lson);
if (qr > m)
sumr += queries(ql, qr, rson);
if (ql<=m && qr>m && rv[lrt]==lv[rrt])
--sumr;
return sumr;
}
void change(int x, int y, int val){
while (top[x] != top[y]){
if (deep[top[x]] < deep[top[y]])
swap(x, y);
update(pos[top[x]], pos[x], val, 1, n, 1);
x = p[top[x]];
}
if (x == y)
return ;
if (deep[x] > deep[y])
swap(x, y);
update(pos[son[x]], pos[y], val, 1, n, 1);
}
int get_find(int pos, int l, int r, int rt){
if (l == r)
return lv[rt];
push_down(l, r, rt);
int m = (l+r)>>1;
if (pos <= m)
return get_find(pos, lson);
return get_find(pos, rson);
}
int seek(int x, int y){
int ans=0, lastu=-1, lastv=-1;
while (top[x] != top[y]){
if (deep[top[x]] < deep[top[y]]){
swap(x, y);
swap(lastu, lastv);
}
ans += queries(pos[top[x]], pos[x], 1, n, 1);
int col = get_find(pos[x], 1, n, 1);
if (col == lastu)
--ans;
lastu = get_find(pos[top[x]], 1, n, 1);
x = p[top[x]];
}
if (x == y){
if (lastu == lastv)
--ans;
return ans;
}
if (deep[x] > deep[y]){
swap(x, y);
swap(lastu, lastv);
}
ans += queries(pos[son[x]], pos[y], 1, n, 1);
int col = get_find(pos[y], 1, n, 1);
if (col == lastv)
--ans;
col = get_find(pos[son[x]], 1, n, 1);
if (col == lastu)
--ans;
return ans;
}
int main(){
while (~scanf("%d%d", &n, &q)){
init();
int a, b, c;
for (int i=1; i