bzoj1455 罗马游戏
Description
罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令: 1. Merger(i, j)。把i所在的团和j所在的团合并成一个团。如果i, j有一个人是死人,那么就忽略该命令。 2. Kill(i)。把i所在的团里面得分最低的人杀死。如果i这个人已经死了,这条命令就忽略。 皇帝希望他每发布一条kill命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报0分)
Input
第一行一个整数n(1<=n<=1000000)。n表示士兵数,m表示总命令数。 第二行n个整数,其中第i个数表示编号为i的士兵的分数。(分数都是[0..10000]之间的整数) 第三行一个整数m(1<=m<=100000) 第3+i行描述第i条命令。命令为如下两种形式: 1. M i j 2. K i
Output
如果命令是Kill,对应的请输出被杀人的分数。(如果这个人不存在,就输出0)
#include
#include
#include
#include
using namespace std;
const int maxn=1000010;
int n,m;
int fa[maxn],die[maxn];
int val[maxn],lef[maxn],rig[maxn],dis[maxn];
int father(int u)
{
while(fa[u]!=u)
{
fa[u]=fa[fa[u]];
u=fa[u];
}
return u;
}
int merge(int x,int y)
{
if(!x) return y;
if(!y) return x;
if(val[x]>val[y]) swap(x,y);
rig[x]=merge(rig[x],y);
fa[rig[x]]=x;//并查
if(dis[rig[x]]>dis[lef[x]]) swap(lef[x],rig[x]);
dis[x]=dis[rig[x]]+1;//如果x没有右孩子,则rig[x]=0,而dis[0]=-1,则dis[x]=0;
return x;
}
int main()
{
int u,v,fu,fv,t;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",val+i);
fa[i]=i;
dis[i]=0;
die[i]=0;
lef[i]=0;
rig[i]=0;
}
dis[0]=-1;
char op[3];
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='M')
{
scanf("%d%d",&u,&v);
if(die[u]||die[v]) continue;
fu=father(u);
fv=father(v);
if(fu==fv) continue;
t=merge(fu,fv);
fa[t]=t;//成为根节点
}
else{
scanf("%d",&v);
if(die[v]) {
printf("0\n");
}
else{
fv=father(v);
die[fv]=1;
printf("%d\n",val[fv]);
t=merge(lef[fv],rig[fv]);
fa[t]=t;//成为根节点
}
}
}
}
https://vjudge.net/problem/HDU-1512
题意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。
题解 :左偏树+并查集
#include
#include
#include
#include
using namespace std;
const int maxn=100010;
int n,m;
int fa[maxn];
int val[maxn],lef[maxn],rig[maxn],dis[maxn];
int father(int u)
{
while(fa[u]!=u)
{
fa[u]=fa[fa[u]];
u=fa[u];
}
return u;
}
int merge(int &x,int &y)
{
if(!x) return y;
if(!y) return x;
if(val[x]dis[lef[x]]) swap(lef[x],rig[x]);
dis[x]=dis[rig[x]]+1;//如果x没有右孩子,则rig[x]=0,而dis[0]=-1,则dis[x]=0;
return x;
}
int pop(int &t)
{
int l=lef[t],r=rig[t];
fa[l]=l;//因为要暂时删掉根,所以左右子树先作为根
fa[r]=r;
lef[t]=rig[t]=dis[t]=0;
return merge(l,r);
}
int main()
{
int u,v,fu,fv,a,b,c;
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++)
{
scanf("%d",val+i);
fa[i]=i;
dis[i]=0;
lef[i]=0;
rig[i]=0;
}
dis[0]=-1;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
fu=father(u);
fv=father(v);
if(fu==fv)
{
printf("-1\n");
continue;
}
val[fu]>>=1;
val[fv]>>=1;
a=pop(fu);
b=pop(fv);
c=merge(a,b);
c=merge(fu,c);
c=merge(fv,c);
printf("%d\n",val[c]);
}
}
}
https://vjudge.net/problem/HDU-3031
题意:喜羊羊和灰太狼比较所持有的卡片的大小,每张卡片上都有一定的点数,有5种操作,如下:
- T K: 拿到第 k 堆所有牌
- C: 喜羊羊和灰太狼手中最大的牌进行比较,赢得一方可以把对方的所有牌全部取过来
- L: 失去手中最大的一张牌
- A P: 手中最大的牌点数加上P
- E Q: 手中最大的牌点数改为Q点
共有R轮比赛,每轮都是双方轮流操作,灰太狼先抽,最后输出输赢即可。
#include
#include
#include
using namespace std;
const int maxn=1000010;
int val[maxn],lef[maxn],rig[maxn],dis[maxn];
int merge(int &x,int &y)
{
if(!x) return y;
if(!y) return x;
if(val[x]=val[root[1]])
{
root[0]=merge(root[0],root[1]);
sum[0]+=sum[1];
root[1]=0;
sum[1]=0;
}
else
{
root[1]=merge(root[0],root[1]);
sum[1]+=sum[0];
root[0]=0;
sum[0]=0;
}
}
else if(op[0]=='L')
{
root[i&1]=pop(root[i&1]);
sum[i&1]--;
}
else if(op[0]=='A')
{
scanf("%d",&v);
val[root[i&1]]+=v;
}
else
{
scanf("%d",&v);
int t=pop(root[i&1]);
val[root[i&1]]=v;
root[i&1]=merge(t,root[i&1]);
}
}
printf("%d:%d\n",sum[0],sum[1]);
if(sum[0]>=sum[1]) Wolffy++;
else Happy++;
}
if(Wolffy>Happy) printf("Hahaha...I win!!\n");
else printf("I will be back!!\n");
}