@nlogn
2019-01-23T10:40:49.000000Z
字数 3119
阅读 588
注:本题解代码均已开启反作弊功能。
18:40比赛就开始了,给我说的时候已经19:20了,,,
我少了40min的做题时间,以至于只拿到了150pts。
自闭了,我菜死了。
强死了啊啊啊啊啊啊啊!
这题面对可爱的真的不太友好(逃
显然我们可以暴力。
从题面得知,这是一棵二叉树,所以满足一个性质:
如果一个节点编号为,那么它的左右子节点编号分别为和.
对于每一次询问,查看这个点是否为Gay
点,如果不是,那么往上跳。
直到调到根节点为止。
/* Headers */
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<iostream>
using namespace std;
namespace FastIO{
const int BUFSIZE=1<<20;
char ibuf[BUFSIZE],*is=ibuf,*it=ibuf;
char obuf[BUFSIZE],*os=obuf,*ot=obuf+BUFSIZE;
inline char getch(){
if(is==it)
it=(is=ibuf)+fread(ibuf,1,BUFSIZE,stdin);
return (is==it)?EOF:*is++;
}
inline int getint(){
int res=0,neg=0,ch=getch();
while(!(isdigit(ch)||ch=='-')&&ch!=EOF)
ch=getch();
if(ch=='-'){
neg=1;ch=getch();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch-'0');
ch=getch();
}
return neg?-res:res;
}
inline void flush(){
fwrite(obuf,1,os-obuf,stdout);
os=obuf;
}
inline void putch(char ch){
*os++=ch;
if(os==ot) flush();
}
inline void putint(int res){
static char q[10];
if(res==0) putch('0');
else if(res<0){
putch('-');
res=-res;
}
int top=0;
while(res){
q[top++]=res%10+'0';
res/=10;
}
while(top--) putch(q[top]);
}
}
using namespace FastIO;
/* definitions */
const int MAXN = 2e6+7;
struct Node{
int father;
bool gay;
};
Node Tree[MAXN];
int n,m,q;
int Gay[MAXN];
int TO[MAXN];
bool PRINT[MAXN];
bool flag;
/* functions */
inline void DFS(int p){
if(p==1){
printf("srO lgy Orz\n");
return;
}
while(p>1){
if(Tree[p].gay==true){
printf("LoGAY!\n");
//PRINT[p]=true;
flag=true;
return;
}
p=Tree[p].father;
//cout<<p<<" ";
}
if(!flag) printf("srO lgy Orz\n");
}
int main(int argc,char *argv[]){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
Tree[x].gay=true;
}
scanf("%d",&q);
for(int i=1;i<=q;i++){
scanf("%d",&TO[i]);
if(TO[i]%2==0)Tree[TO[i]].father=TO[i]/2;
else Tree[TO[i]].father=(TO[i]-1)/2;
DFS(TO[i]);
}
fclose(stdin);
fclose(stdout);
return 0;
}
怎么这么惨啊QAQ(再逃
其实看到这题,我第一反应是:
普及组考Treap!
而我只是知道Treap可以求区间第小,而且还是的,具体实现,连原理我都不知道啊啊啊啊啊啊。
心态崩了,每日一崩。
但实际上不用,虽然大神犇说可以线段树+二分
当时我心态就又崩了,我是不是学了假的线段树啊啊啊啊啊。(一定是我太菜了)
用两个堆维护求区间第小值的查询。(一个大根堆,一个小根堆)
对于每一次输入的2
操作,我们定义一个r=q+1
,然后从r
循环到q
,把1
操作的东西插入进大根堆,如果这时大跟堆中有个元素,那么就把大根堆的堆顶push
进小根堆里。
如此循环执行之后,输出小根堆堆顶即可。
附图自行理解:
/* Headers */
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
/* definitions */
const int MAXN = 2e6+7;
priority_queue<int,vector<int>,greater<int> > MinQ;
priority_queue<int> MaxQ;
int Buck[MAXN];
int n,m,q;
int r=1;
/* functions */
inline void Queue(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&Buck[i]);
for(int i=1;i<=m;i++){
scanf("%d",&q);
for(int j=r;j<q;j++){
MaxQ.push(Buck[j]);
if(MaxQ.size()==i){
MinQ.push(MaxQ.top());
MaxQ.pop();
}
}
r=q+1;
printf("%d\n",MinQ.top());
MaxQ.push(MinQ.top());
MaxQ.pop();
}
return;
}
int main(int argc,char *argv[]){
freopen("bucket.in","r",stdin);
freopen("bucket.out","w",stdout);
Queue();
fclose(stdin);
fclose(stdout);
return 0;
}
首先我们一眼就能找到的规律。
inline void init(){
int ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
ans+=x;
}
for(int j=1;j<=m;j++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
Add_Edge(a,b,c);
Add_Edge(a,b,c)
}
printf("%d\n",ans);
}
大爷不肯给我讲啊啊啊啊啊,怎么办啊啊啊啊啊啊,
一定是我太菜了,滚~