就推荐几个有营养的题好了
由于最终状态悬挂在桌面以下的长度始终是不变的,因此可以枚举最终哪个端点悬挂在最下面,然后二分找到能去掉的最多的开头的部分
K - Tree Queries Online(SGU 550)
给你一棵树,每条边都有一个标号,然后给你一个删边的顺序,每删除一条边,就要输出这条边的边权,然后数一下当前块两边各有多少个点,给点少的那一半的每条边都乘上当前边的边权,给多的那一半都加上当前边的边权。
这一看就是个裸的数据结构题啊,但是,有简单做法。。。
每次暴力搜索两个块,当一边无法扩展更多的点的时候就停止,然后点少的那一边暴力修改每条边的标记,多的那一边加个懒惰标记,维护一个delta变量就好了,表示这一块被加了多少。
说起来简单,写起来的时候要相当注意,一不小心就超时了。往两边同时搜的时候要好好设计,边的访问量可能会很大
每次删除一条边之后实际上可以用邻接表删除这条边,即多记录一个pre,每次将pre的next指向next
如果使用上述方法要注意这样的数据,一个点的度数为n-1,其他点的度数都为1,然后顺时针或者逆时针删边。
其实数据还是挺弱的,没有逆时针删边的顺序,所以加上邻接表的优化后也没有块多少
这题还可以splay,改天再补。
#include <cstdio>
#include <set>
#include <time.h>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 400010;
const int mod = 99990001;
typedef long long lld;
int n;
struct Edge {
int pre;
int s, t, w;
int id, next;
} edge[N * 2];
int head[N];
struct Data {
int s, t, w;
Data() {
}
Data(int _s, int _t, int _w) :
s(_s), t(_t), w(_w) {
}
} edge_src[N];
int E, Btype, Belong[N], ADD[N], cur[N];
void add_edge(int a, int b, int w, int id) {
edge[E].s = a;
edge[E].t = b;
edge[E].id = id;
edge[E].next = head[a];
if (head[a] != -1)
edge[head[a]].pre = E;
head[a] = E;
cur[a] = E++;
}
void init() {
Btype = 1;
E = 0;
memset(cur, -1, sizeof(cur));
memset(head, -1, sizeof(head));
}
int Q[N], q[N];
int he1, ta1;
int he2, ta2;
int ss, tt;
int DFN;
bool vis[N];
int MI_1, MI_2;
int rec[N];
int T,T1,T2;
int QQQ[N],Tot_Q;
void destroy() { // update vis[]
for(int i = 1; i <= Tot_Q; i++) {
vis[QQQ[i]]=false;
cur[QQQ[i]] = head[QQQ[i]];
}
}
int another;
void split_set(int s, int wi) {
int ori = Belong[another];
Belong[s] = ++Btype;
ADD[Btype] = 0;
int he = 0, ta = 0;
rec[++ta] = s;
while (he < ta) {
int now = rec[++he];
Belong[now] = Btype;
vis[now] = false;
for (int i = head[now]; i != -1; i = edge[i].next) {
T2++;
int v = edge[i].t;
if (v == another)
continue;
if (vis[v]) {
int id = edge[i].id;
if (ADD[ori]) {
edge_src[id].w += ADD[ori];
if (edge_src[id].w >= mod)
edge_src[id].w -= mod;
}
lld tmp = (lld) edge_src[id].w * wi;
if (tmp >= mod)
tmp %= mod;
edge_src[id].w = tmp;
rec[++ta] = v;
}
}
}
ADD[ori] += wi;
if (ADD[ori] >= mod)
ADD[ori] -= mod;
}
void split(int s, int t, int wi, int id) {
MI_1 = MI_2 = 1000000;
DFN = Belong[s];
he1 = ta1 = he2 = ta2 = 0;
Q[++ta1] = s;
q[++ta2] = t;
vis[s] = vis[t] = true;
Tot_Q = 0;
while (true) {
bool f1 = false;
while (he1 < ta1) {
int now = Q[he1 + 1];
if (now < MI_1)
MI_1 = now;
for (int i = cur[now]; i != -1; i = edge[i].next) {
T++;
int v = edge[i].t;
if (Belong[v] == DFN && !vis[v]) {
vis[v] = true;
QQQ[++Tot_Q] = v;
Q[++ta1] = v;
cur[now] = edge[i].next;
f1 = true;
break;
}
}
if (f1)
break;
cur[now] = head[now];
++he1;
}
bool f2 = false;
while (he2<ta2) {
int now = q[he2 + 1];
if (now < MI_2)
MI_2 = now;
for (int i = cur[now]; i != -1; i = edge[i].next) {
T++;
int v = edge[i].t;
if (Belong[v] == DFN && !vis[v]) {
vis[v] = true;
QQQ[++Tot_Q] = v;
q[++ta2] = v;
cur[now] = edge[i].next;
f2 = true;
break;
}
}
if (f2)
break;
cur[now] = head[now];
++he2;
}
if (!f1 && !f2) {
if (MI_1 < MI_2) {
another = t;
split_set(s, wi);
} else {
another = s;
split_set(t, wi);
}
} else if (!f1) {
another = t;
split_set(s, wi);
} else if (!f2) {
another = s;
split_set(t, wi);
}
if (!f1 || !f2) {
vis[s] = vis[t] = false;
cur[s] = head[s];
cur[t] = head[t];
destroy();
break;
}
}
}
int main() {
//Reopen("a.txt", "r", stdin);
//freopen("b.txt","w",stdout);
int a, b, w, id;
init();
scanf("%d", &n);
double start = clock();
for (int i = 1; i < n; i++) {
scanf("%d%d%d", &a, &b, &w);
add_edge(a, b, w, i);
add_edge(b, a, w, i);
edge_src[i] = Data(a, b, w);
}
for (int i = 1; i <= n; i++)
Belong[i] = 1;
for (int i = 1; i < n; i++) {
scanf("%d", &id);
int s = edge_src[id].s;
int t = edge_src[id].t;
int w = edge_src[id].w;
printf("%d\n",(w + ADD[Belong[s]]) % mod);
fflush(stdout);
split(s, t, (w + ADD[Belong[s]]) % mod, id);
int ed1 = (id - 1) * 2;
if (head[s] == ed1) {
head[s] = edge[head[s]].next;
cur[s] = head[s];
} else {
edge[edge[ed1].pre].next = edge[ed1].next;
if(~edge[ed1].next)edge[edge[ed1].next].pre = edge[ed1].pre;
}
int ed2 = (id - 1) * 2 + 1;
if (head[t] == ed2) {
head[t] = edge[head[t]].next;
cur[t] = head[t];
} else {
edge[edge[ed2].pre].next = edge[ed2].next;
if(~edge[ed2].next)edge[edge[ed2].next].pre = edge[ed2].pre;
}
}
return 0;
}