4336: BJOI2015 骑士的旅行
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 282 Solved: 123
[ Submit][ Status][ Discuss]
Description
在一片古老的土地上,有一个繁荣的文明。
这片大地几乎被森林覆盖,有N座城坐落其中。巧合的是,这N座城由恰好N-1条双
向道路连接起来,使得任意两座城都是连通的。也就是说,这些城形成了树的结构,任意两
座城之间有且仅有一条简单路径。
在这个文明中,骑士是尤其受到尊崇的职业。任何一名骑士,都是其家族乃至家乡的荣
耀。Henry从小就渴望成为一名能守护家乡、驱逐敌人的骑士。勤奋训练许多年后,Henry
终于满18岁了。他决定离开家乡,向那些成名已久的骑士们发起挑战!
根据Henry的调查,大陆上一共有M名受封骑士,不妨编号为1到M。
第i个骑士居住在城Pi,武力值为Fi。
Henry计划进行若干次旅行,每次从某座城出发沿着唯一的简单路径前往另一座城,
同时会挑战路线上武力值最高的K个骑士(Henry的体力有限,为了提高水平,当然要挑
战最强的骑士)。如果路线上的骑士不足K人,Henry会挑战遇到的所有人。
每次旅行前,可能会有某些骑士的武力值或定居地发生变化,Henry自然会打听消息,
并对计划做出调整。
为了在每次旅行时做好充分准备,Henry希望你能帮忙在每次旅行前计算出这条路线
上他将挑战哪些对手。
Input
第一行,一个整数N,表示有N座城,编号为1~N。
接下来N-1行,每行两个整数Ui和Vi,表示城Ui和城Vi之间有一条道路相连。
第N+1行,一个整数M,表示有M个骑士。
接下来M行,每行两个整数Fi和Pi。按顺序依次表示编号为1~M的每名骑士的武
力值和居住地。
第N+M+2行,两个整数Q,K,分别表示操作次数和每次旅行挑战的骑士数目上限。
接下来Q行,每行三个整数Ti,Xi,Yi。Ti取值范围为{1,2,3},表示操作类型。
一共有以下三种类型的操作:
Ti=1时表示一次旅行,Henry将从城Xi出发前往城市Yi;
Ti=2时表示编号为Xi的骑士的居住地搬到城Yi;
Ti=3时表示编号为Xi的骑士的武力值修正为Yi。
Output
输出若干行,依次为每个旅行的答案。
对每个Ti=1的询问,输出一行,按从大到小的顺序输出Henry在这次旅行中挑战的
所有骑士的武力值。如果路线上没有骑士,输出一行,为一个整数-1。
Sample Input
5
1 2
1 3
2 4
2 5
4
10 1
6 1
14 5
7 3
5 3
1 2 3
1 5 3
1 4 4
2 1 4
1 2 3
1 2
1 3
2 4
2 5
4
10 1
6 1
14 5
7 3
5 3
1 2 3
1 5 3
1 4 4
2 1 4
1 2 3
Sample Output
10 7 6
14 10 7
-1
7 6
14 10 7
-1
7 6
HINT
100%的数据中,1 ≤ N, M ≤ 40,000,1 ≤ Ui, Vi, Pi ≤ N,1 ≤ Q ≤ 80,000, 1 ≤ K ≤
20,旅行次数不超过 40,000 次,武力值为不超过1,000的正整数。
Source
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
struct Knight{
int Atk,Num;
Knight(){}
Knight(int Atk,int Num): Atk(Atk),Num(Num){}
bool operator < (const Knight &b) const {return Atk < b.Atk;}
};
const int maxn = 4E4 + 40;
const int INF = ~0U>>1;
typedef __gnu_pbds::priority_queue<Knight,less<Knight>,__gnu_pbds::pairing_heap_tag> Heap;
int n,m,q,K,ch[maxn][2],rev[maxn],fa[maxn],pfa[maxn],Atk[maxn],ansnum[maxn]
,Liv[maxn],va[maxn],Max[maxn],pos[maxn],ansAtk[21],anspos[21];
Heap Q[maxn];
Heap::point_iterator id[maxn];
void pushdown(int x)
{
if (rev[x]) {
swap(ch[x][0],ch[x][1]);
if (ch[x][0]) rev[ch[x][0]] ^= 1;
if (ch[x][1]) rev[ch[x][1]] ^= 1;
rev[x] ^= 1;
}
}
void maintain(int x)
{
Max[x] = va[x]; pos[x] = x;
for (int i = 0; i < 2; i++)
if (ch[x][i] && Max[ch[x][i]] > Max[x])
Max[x] = Max[ch[x][i]],pos[x] = pos[ch[x][i]];
}
void rotate(int x)
{
int y = fa[x],z = fa[y];
pfa[x] = pfa[y]; pfa[y] = 0;
int d = ch[y][0] == x?0:1;
ch[y][d] = ch[x][d^1]; maintain(y);
fa[ch[y][d]] = y; ch[x][d^1] = y;
fa[x] = z; fa[y] = x; maintain(x);
if (z) ch[z][ch[z][1] == y] = x,maintain(z);
}
stack <int> s;
void splay(int x)
{
for (int now = x; now; now = fa[now]) s.push(now);
while (!s.empty()) {pushdown(s.top()); s.pop();};
for (int y; y = fa[x]; rotate(x))
if (fa[y])
rotate((ch[fa[y]][0] == y)^(ch[y][0] == x)?x:y);
}
void Access(int x)
{
for (int u = x,v = 0; u; v = u,u = pfa[u]) {
splay(u);
if (ch[u][1]) fa[ch[u][1]] = 0,pfa[ch[u][1]] = u;
ch[u][1] = v; maintain(u);
if (v) fa[v] = u,pfa[v] = 0;
}
}
void ChangeRoot(int x) {Access(x); splay(x); rev[x] ^= 1;}
void Join(int x,int y) {ChangeRoot(x); pfa[x] = y; splay(y);}
void Rebuild(int x)
{
ChangeRoot(x);
Knight k = Q[x].top();
va[x] = k.Atk; maintain(x);
}
int getint()
{
char c = getchar();
int ret = 0;
while (c < '0' || '9' < c) c = getchar();
while ('0' <= c && c <= '9') ret = ret*10 + c - '0',c = getchar();
return ret;
}
int main()
{
//freopen("DMC.txt","r",stdin);
n = getint();
for (int i = 1; i <= n; i++) {
va[i] = Max[i] = -INF; pos[i] = i;
Q[i].push(Knight(-INF,0));
}
for (int i = 1; i < n; i++) {
int x = getint(),y = getint();
Join(x,y);
}
m = getint();
for (int i = 1; i <= m; i++) {
Atk[i] = getint(); Liv[i] = getint();
id[i] = Q[Liv[i]].push(Knight(Atk[i],i));
Rebuild(Liv[i]);
}
q = getint(); K = getint();
while (q--) {
int typ = getint();
if (typ == 1) {
int l = getint(),r = getint(),tot = 0;
for (int i = 1; i <= K; i++) {
ChangeRoot(l); Access(r); splay(r);
if (Max[r] > 0) {
ansAtk[++tot] = Max[r];
anspos[tot] = pos[r];
Knight k = Q[anspos[tot]].top();
ansnum[tot] = k.Num;
Q[anspos[tot]].pop();
Rebuild(anspos[tot]);
}
else break;
}
if (!tot) {puts("-1"); continue;}
else {
for (int i = 1; i <= tot; i++) {
printf("%d ",ansAtk[i]);
id[ansnum[i]] = Q[anspos[i]].push(Knight(ansAtk[i],ansnum[i]));
Rebuild(anspos[i]);
}
puts("");
}
}
else if (typ == 2) {
int num = getint(),to = getint();
Q[Liv[num]].erase(id[num]);
Rebuild(Liv[num]);
id[num] = Q[Liv[num] = to].push(Knight(Atk[num],num));
Rebuild(Liv[num]);
}
else {
int num = getint(),modi = getint();
Q[Liv[num]].erase(id[num]);
id[num] = Q[Liv[num]].push(Knight(Atk[num] = modi,num));
Rebuild(Liv[num]);
}
}
return 0;
}