[Codefroces536E]Tavas on the Path && 树链剖分

第二次写树链剖分 然后一直WA 一直WA 然后就对着标程改 终于在一下午和一晚上的折磨过后A了这道题 QAQ

首先把询问离线化 并按照值从大到小排序 对边的处理同理 这样我们就可以 只枚举每条边一次 

然后对于线段树上的每一个节点 我们保存左边的1的长度 右边的1的长度 1的总长度 和根据f计算后的sum值 

询问的时候找出x, y的LCA p 然后询问x到p的路径和y到p的路径 注意要把其中一条路径反转过来才能正常的询问 要注意特殊处理

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
#define ls (i<<1)
#define rs ((i<<1)|1)
using namespace std;
typedef long long LL;
const int MAXN = 100000;
const int INF = 0x3f3f3f3f;
int n, m, q, tx = 0;
int f[MAXN+10];
// Edges
struct node {
	int v, next;
} Edge[MAXN*2+10];
int adj[MAXN+10], ecnt;
inline void addedge(int u, int v) {
	node &e = Edge[++ecnt];
	e.v = v; e.next = adj[u]; adj[u] = ecnt;
}
inline void add(int u, int v) {
	addedge(u, v); addedge(v, u);
}

// DFS
int F[MAXN+10][20], son[MAXN+10], idx[MAXN+10], dep[MAXN+10];
int sz[MAXN+10], top[MAXN+10], dfn, length[MAXN+10];
void dfs(int u, int fa) {
	son[u] = n+1; F[u][0] = fa; sz[u] = 1;
	for(int i = 1; i < 20; i++) F[u][i] = F[F[u][i-1]][i-1];
	for(int i = adj[u]; i; i = Edge[i].next) {
		int v = Edge[i].v;
		if(v == fa) continue;
		dep[v] = dep[u] + 1;
		dfs(v, u);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	}
	if(son[u] == n+1) son[u] = u;
}
void Getid(int u, int tp) {
	top[u] = tp;
	if(son[u] != u) length[son[u]]++;
	if(son[u] != u) Getid(son[u], top[u]);
	for(int i = adj[u]; i; i = Edge[i].next) {
		int v = Edge[i].v;
		if(v == F[u][0] || v == son[u]) continue;
		Getid(v, v);
	}
}
void DFS(int u, int fa) {
	if(u != son[u]) length[top[u]]++;
	for(int i = adj[u]; i; i = Edge[i].next) {
		int v = Edge[i].v;
		if(v != fa) DFS(v, u);
	}
}
// seg tree
struct Node {
	int fr, ba, sum, len;
	Node () {}
	Node (int a, int b, int c, int d) : fr(a), ba(b), sum(c), len(d) {}
} ;
Node merge(Node a, Node b) {
	Node ans;
	ans.sum = a.sum + b.sum - f[a.ba] - f[b.fr] + f[a.ba+b.fr];
	ans.len = a.len + b.len;
	ans.fr = a.fr; ans.ba = b.ba;
	if(a.fr == a.len) ans.fr += b.fr;
	if(b.ba == b.len) ans.ba += a.ba;
	return ans;
}
struct Seg_Tree {
	Node tree[MAXN*4+10];
	void Build(int i, int L, int R) {
		Node &u = tree[i];
		u.fr = u.ba = u.sum = 0;
		u.len = R-L;
		if(R-L == 1) return ;
		int mid = (L+R) >> 1;
		Build(ls, L, mid);
		Build(rs, mid, R);
	}
	void add(int i, int L, int R, int x) {
		Node &u = tree[i];
		if(R-L == 1) {
			u.fr = u.ba = 1; u.sum = f[1]; return ;
		}
		int mid = (L+R) >> 1;
		if(x < mid) add(ls, L, mid, x);
		else add(rs, mid, R, x);
		u = merge(tree[ls], tree[rs]);
	}
} seg;
// LCA
int Go(int x, int k) {
	for(int i = 0; i <= 17; i++) 
		if((1<<i) & k) 
			x = F[x][i];
	return x;
}
int LCA(int x, int y) {
	if(dep[x] < dep[y]) swap(x, y);
	x = Go(x, dep[x] - dep[y]);
	if(x == y) return x;
	for(int i = 17; i >= 0; i--)
		if(F[x][i] != F[y][i])
			x = F[x][i], y = F[y][i];
	return F[x][0];
}
// Get Path imformation
Node GetNode(int l, int r, int i, int L, int R) {
	if(l <= L && R <= r) return seg.tree[i];
	if(R <= l || r <= L) return Node(0, 0, 0, 0);
	int mid = (L+R) >> 1;
	return merge(GetNode(l, r, ls, L, mid), GetNode(l, r, rs, mid, R));
}
bool act[MAXN+10];
Node Doit(int x, int y) {
	Node ret(0, 0, 0, 0);
	while(dep[x] > dep[y]) {
		if(top[x] == x) {
			if(act[x]) ret = merge(Node(1, 1, f[1], 1), ret);
			else ret = merge(Node(0, 0, 0, 1), ret);
			x = F[x][0];
		}
		else {
			int R = idx[top[x]] + dep[x] - dep[top[x]];
			int L = idx[top[x]];
			if(top[x] == top[y]) L = idx[top[x]] + dep[y] - dep[top[x]];
			ret = merge(GetNode(L, R, 1, 0, n), ret);
			x = top[x];
		}
	}
	return ret;
}
// Make an 0 to 1
void active(int u, int v) {
	if(dep[u] < dep[v]) swap(u, v);
	if(u != top[u]) seg.add(1, 0, n, idx[top[u]] + dep[u] - dep[top[u]] - 1);
	else act[u] = true;
}
// Main
struct edge {
	int u, v, wt;
	bool operator < (const edge &t) const {
		return wt < t.wt || (wt == t.wt && u < t.u) || (wt == t.wt && u == t.u && v < t.v);
	}
} E[MAXN+10];
struct QUE {
	int x, u, v, id;
	bool operator < (const QUE &t) const {
		return x < t.x || (x == t.x && u < t.u) || (x == t.x && u == t.u && v < t.v);
	}
} Q[MAXN+10];
int Ans[MAXN+10];
int main() {
	SF("%d%d", &n, &q);
	
	seg.Build(1, 0, n);
	
	for(int i = 1; i < n; i++) SF("%d", &f[i]);
	for(int i = 1; i < n; i++) {
		SF("%d%d%d", &E[i].u, &E[i].v, &E[i].wt);
		add(E[i].u-1, E[i].v-1);
	}
	
	for(int i = 0; i < n; i++) top[i] = i;
	
	dfs(0, 0);
	Getid(0, 0);
	DFS(0, 0);
	
	int cnt = 0;
	for(int i = 0; i < n; i++)
		if(top[i] == i) {
			idx[i] = cnt;
			cnt += length[i];
		}
	
	for(int i = 1; i <= q; i++) {
		SF("%d%d%d", &Q[i].u, &Q[i].v, &Q[i].x);
		Q[i].id = i;
	}
	sort(E+1, E+n); sort(Q+1, Q+q+1);
	reverse(E+1, E+n); reverse(Q+1, Q+1+q);

	int P = 1;
	for(int i = 1; i <= q; i++) {
		while(P < n && E[P].wt >= Q[i].x) active(E[P].u-1, E[P].v-1), P++;
		int u = Q[i].u-1, v = Q[i].v-1;
		int lca = LCA(u, v);	
		if(u == lca) swap(u, v);
		Node x = Doit(v, lca);
		Node y = Doit(u, lca);
		swap(x.fr, x.ba);
		Node ret = merge(x, y);
		Ans[Q[i].id] = ret.sum;
	}
	for(int i = 1; i <= q; i++) PF("%d\n", Ans[i]);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值