Codeforces 575B Bribe数链剖分+离线+区间端点打标记

传送门

B. Bribes
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Ruritania is a country with a very badly maintained road network, which is not exactly good news for lorry drivers that constantly have to do deliveries. In fact, when roads are maintained, they become one-way. It turns out that it is sometimes impossible to get from one town to another in a legal way – however, we know that all towns are reachable, though illegally!

Fortunately for us, the police tend to be very corrupt and they will allow a lorry driver to break the rules and drive in the wrong direction provided they receive ‘a small gift’. There is one patrol car for every road and they will request 1000 Ruritanian dinars when a driver drives in the wrong direction. However, being greedy, every time a patrol car notices the same driver breaking the rule, they will charge double the amount of money they requested the previous time on that particular road.

Borna is a lorry driver that managed to figure out this bribing pattern. As part of his job, he has to make K stops in some towns all over Ruritania and he has to make these stops in a certain order. There are N towns (enumerated from 1 to N) in Ruritania and Borna’s initial location is the capital city i.e. town 1. He happens to know which ones out of the N - 1 roads in Ruritania are currently unidirectional, but he is unable to compute the least amount of money he needs to prepare for bribing the police. Help Borna by providing him with an answer and you will be richly rewarded.

Input

The first line contains N, the number of towns in Ruritania. The following N - 1 lines contain information regarding individual roads between towns. A road is represented by a tuple of integers (a,b,x), which are separated with a single whitespace character. The numbers a and b represent the cities connected by this particular road, and x is either 0 or 1: 0 means that the road is bidirectional, 1 means that only the a → b direction is legal. The next line contains K, the number of stops Borna has to make. The final line of input contains K positive integers s1, …, sK: the towns Borna has to visit.

  • 1 ≤ N ≤ 105
  • 1 ≤ K ≤ 106
  • 1 ≤ a, b ≤ N for all roads
  • for all roads
  • 1 ≤ si ≤ N for all 1 ≤ i ≤ K
Output

The output should contain a single number: the least amount of thousands of Ruritanian dinars Borna should allocate for bribes, modulo 109 + 7.

Sample test(s)
Input
5
1 2 0
2 3 0
5 1 1
3 4 1
5
5 4 5 2 2
Output
4
Note

Borna first takes the route 1 → 5 and has to pay 1000 dinars. After that, he takes the route 5 → 1 → 2 → 3 → 4 and pays nothing this time. However, when he has to return via 4 → 3 → 2 → 1 → 5, he needs to prepare 3000 (1000+2000) dinars. Afterwards, getting to 2 via 5 → 1 → 2 will cost him nothing. Finally, he doesn't even have to leave town 2 to get to 2, so there is no need to prepare any additional bribe money. Hence he has to prepare 4000 dinars in total.

题意:在一棵树上,有一些边是单向边,有一些是双向边。如果逆向行驶单向边,第一次逆行这条边,罚款1,……第i次罚款2^i.

然后给出k个点,分别为ki,到达ki后再去ki+1,初始的时候在1点。问按照上面的安排,最少被罚多少。%10^9+7

思路:将询问离线后,求出每条单向边被反向走了多少次。将单向边分为往上走为逆向和往下走为逆行的两类。对于每一次询问,可采取将这个树进行剖分后,在重链上走动,重链上的点的dfs序是连续的。先从起点往上走到lca。区间内的第一类反向边都被走了一次。这些区间的首尾打上标记。再从lca走到终点,区间内的第二类反向边被走了一次。打上标记。最后从1-n扫一次,算出每条单向边反行了多少次,就能算出答案了。。注意,,边权下方到儿子节点。

#include
#include
#include
#include
typedef __int64 LL;
const LL MOD = 1000000007;
using namespace std;
const int maxn = 100005;
struct EDGE
{
	int to, next;
	EDGE() {}
	EDGE(int to, int next) :to(to), next(next) {}
}edge[maxn << 1];
int head[maxn], edgecnt;
inline void add(int s, int t)
{
	edge[edgecnt] = EDGE(t, head[s]);
	head[s] = edgecnt++;
}
int anc[maxn][17], dep[maxn], Size[maxn], v[2][maxn], tid[maxn], top[maxn];
void dfs(int u, int fa, int deep)
{
	anc[u][0] = fa;
	dep[u] = deep;
	for (int i = 1; i < 17; i++)
		if (dep[u]>(1 << i))
			anc[u][i] = anc[anc[u][i - 1]][i - 1];
	Size[u] = 1;
	for (int i = head[u]; ~i; i = edge[i].next)
	{
		int v = edge[i].to;
		if (v == fa) continue;
		dfs(v, u, deep + 1);
		Size[u] += Size[v];
	}
}
int dfsclk;
void dfs2(int u)
{
	tid[u] = ++dfsclk;
	int c = 0, s = 0;
	for (int i = head[u]; ~i; i = edge[i].next)
	{
		int v = edge[i].to;
		if (v == anc[u][0]) continue;
		if (Size[v] > s)
		{
			s = Size[v];
			c = v;
		}
	}
	if (c)
	{
		top[c] = top[u];
		dfs2(c);
	}
	for (int i = head[u]; ~i; i = edge[i].next)
	{
		int v = edge[i].to;
		if (v == anc[u][0] || v == c) continue;
		top[v] = v;
		dfs2(v);
	}
}
int lca(int u, int v)
{
	if (dep[u] < dep[v]) swap(u, v);
	for (int i = 16; i >= 0; i--) if (dep[u] - dep[v] >= (1 << i)) u = anc[u][i];
	if (u == v) return u;
	for (int i = 16; i >= 0; i--)
		if (anc[u][i] != anc[v][i])
		{
			u = anc[u][i];
			v = anc[v][i];
		}
	return anc[u][0];
}
int cnt[maxn][2];

void que(int s, int t)
{
	if (s == t) return;
	int l = lca(s, t);
	while (top[s] != top[l])
	{
		cnt[tid[s]][0]++;
		cnt[tid[top[s]] - 1][0]--;
		s = anc[top[s]][0];
	}
	if (s != l)
	{
		cnt[tid[s]][0]++;
		cnt[tid[l]][0]--;
	}
	while (top[t] != top[l])
	{
		cnt[tid[t]][1]++;
		cnt[tid[top[t]] - 1][1]--;
		t = anc[top[t]][0];
	}
	if (t != l)
	{
		cnt[tid[t]][1]++;
		cnt[tid[l]][1]--;
	}
}
LL b[1000005];
LL B[1000005];
void init()
{
	b[1] = 1;
	B[1] = 1;
	for (int i = 2; i <= 1000004; i++)
	{
		b[i] = b[i - 1] * 2 % MOD;
		B[i] = (b[i] + B[i - 1]) % MOD;
	}
	memset(cnt, 0, sizeof(cnt));
	memset(head, -1, sizeof(head));
	memset(anc, 0, sizeof(anc));
	memset(v, 0, sizeof(v));
	edgecnt = 0;
	top[1] = 1;
	dfsclk = 0;
}
struct E
{
	int s, t, l;
}e[maxn];
int main()
{
	init();
	int n;
	scanf("%d", &n);
	for (int i = 1; i < n; i++)
	{
		scanf("%d %d %d", &e[i].s, &e[i].t, &e[i].l);
		add(e[i].s, e[i].t);
		add(e[i].t, e[i].s);
	}
	dfs(1, 0, 1);
	dfs2(1);
	for (int i = 1; i < n; i++)
	{
		if (e[i].l == 0) continue;
		if (dep[e[i].s]>dep[e[i].t])
			v[1][tid[e[i].s]] = 1;
		else
			v[0][tid[e[i].t]] = 1;
	}
	int k;
	scanf("%d", &k);
	int last = 1;
	LL ans = 0;
	while (k--)
	{
		int x;
		scanf("%d", &x);
		que(last, x);
		last = x;
	}
	LL sum[2] = { 0 };
	for (int i = n; i >= 1; i--)
	{
		sum[0] += cnt[i][0];
		sum[1] += cnt[i][1];
		if (v[0][i]) ans = (ans + B[sum[0]]) % MOD;
		if (v[1][i]) ans = (ans + B[sum[1]]) % MOD;
	}
	printf("%I64d\n", ans);
	return 0;
}



你可能感兴趣的:(数据结构)