codeforces 1137D & 1137E & 1137F

codeforces 1137D & 1137E & 1137F


  • D

分成三组(A,B,C)然后先{A,B} , {A} k次直到A,B相遇

发现k%c=0,且k<t+c(否则都可以减c)然后发现A,B到目标需要a*c+c+t-k 次,C需要t次,于是你直接走直到两个相遇就一定是目标点了。

代码

#include<bits/stdc++.h>
using namespace std;

int group[20];

inline void Move(vector<int> S){
	printf("next ");
	for(size_t i=0;i<S.size();i++){
		printf("%d ",S[i]);
	}puts("");
	fflush(stdout);
	int t;scanf("%d",&t);
	for(int T=1;T<=t;T++){
		char x=0;
		while(x<'0'||x>'9')x=getchar();
		while(x>='0'&&x<='9')group[x-'0']=T,x=getchar();
	}
}
int a[]= {0,1,2,3,4,5,6,7,8,9};
vector<int> fast(1,0),slow(1,1),others(a+2,a+10);
vector<int> total(a,a+2),all(a,a+10);
int main()
{
//	cout<<fast[0]<<" "<<slow[0]<<" "<<total[0]<<endl;
	while(true){
		Move(total);
		Move(fast);
		if(group[1]==group[0])break;
	}
	while(true){
		Move(all);
		if(group[1]==group[2])break;
	}
	puts("done");
}
  • E

因为后面一定比前面加的多,可以直接维护一个类似凸包的东西,每次向后加一个,加前面相当于清空,就线性了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;
ll totlen=1;int m;
struct data{
	ll id,b,s;
	data(ll id=0):id(id),b(0),s(0){}
}t[N];
int top=1;

ll calcsum(int i){
	ll b=i==top?t[i].b:t[i].b+t[i+1].b;
	ll s=i==top?t[i].s:t[i].s+t[i+1].s;
	return b+(ll)(t[i].id-1ll)*s;
}

int main()
{
	cin>>totlen>>m;
	t[1]=data(1);
	while(m--){
		int opt=0;scanf("%d",&opt);
		if(opt==1){
			ll sum;
			scanf("%lld",&sum);
			totlen+=sum;
			t[top=1]=data(1);
		}else if(opt==2){
			ll sum;
			scanf("%lld",&sum);
			while(top>1){
				ll T1=calcsum(top);
				ll T2=calcsum(top-1);
				ll sub1=totlen+1ll-t[top].id;
				ll sub2=totlen+1ll-t[top-1].id;
				if((long double)T1*sub2 >= (long double)T2*sub1){
					t[top-1].b+=t[top].b;
					t[top-1].s+=t[top].s;
					--top;
				}else break;
			}
			t[++top]=data(totlen+1);

			totlen+=sum;
			// cout<<"!"<<endl;
			// cout<<calcsum(top)<<endl;
		}else{
			ll b,s;
			scanf("%lld%lld",&b,&s);
			t[top].b+=b;
			t[top].s+=s;
		}
		while(top>1){
			ll T=calcsum(top),T2=calcsum(top-1);
			if(T>=T2){
				t[top-1].b+=t[top].b;
				t[top-1].s+=t[top].s;
				--top;
			}else break;
		}
//		cout<<calcsum(top-1)<<endl;
//		for(int i=1;i<=top;i++)cout<<t[i].id<<" , ";puts("");
		printf("%lld %lld\n",t[top].id,calcsum(top));
	}
}
  • F

因为无论如何都有两个叶子节点,那最大的一定是最后一个,然后每次就相当于是把之前最大的和新的最大的这条链的点全部提到最后面。发现这个非常像LCT的换根操作,在access的时候维护一下每个段的长度就行了

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,T;
struct Splay{
	int ch[2],fa;bool rev;
	int col,paint,sz;
}t[N];
int cnt,null=0;
inline bool isroot(int x){return t[t[x].fa].ch[1]!=x&&t[t[x].fa].ch[0]!=x;}
inline bool son(int x){return t[t[x].fa].ch[1]==x;}

inline void pushup(int x){t[x].sz=t[t[x].ch[1]].sz+t[t[x].ch[0]].sz+1;}
inline void pushdown(int x){
	if(t[x].rev){
		swap(t[x].ch[0],t[x].ch[1]);
		if(t[x].ch[0])t[t[x].ch[0]].rev^=1;
		if(t[x].ch[1])t[t[x].ch[1]].rev^=1;
		t[x].rev=0;
	}
	if(t[x].paint){
		t[x].col=t[x].paint;
		if(t[x].ch[1])t[t[x].ch[1]].paint=t[x].paint;
		if(t[x].ch[0])t[t[x].ch[0]].paint=t[x].paint;
		t[x].paint=0;
	}
}
inline void pushnow(int x){
	if(!isroot(x))pushnow(t[x].fa);
	pushdown(x);
}

inline void rotate(int x){
	int f=t[x].fa,g=t[t[x].fa].fa;
	bool a=son(x),b=son(x)^1;
	if(!isroot(f))t[g].ch[son(f)]=x;
	t[x].fa=g;
	t[t[x].ch[b]].fa=f;t[f].ch[a]=t[x].ch[b];
	t[x].ch[b]=f;t[f].fa=x;
	pushup(f);pushup(x);
}

inline void splay(int x){
	pushnow(x);
	while(!isroot(x)){
		int f=t[x].fa;
		if(!isroot(f)){
			if(son(x)^son(f))rotate(x);
			else rotate(f);
		}
		rotate(x);
	}
}
#define lowbit(x) (x&(-x))
struct fenwick{
	int t[N<<1],n;
	void set(int _n){n=_n;}
	inline void add(int x,int y){
		for(;x<=n;x+=lowbit(x))t[x]+=y;
	}
	inline int qry(int x){
		int ans=0;for(;x;x-=lowbit(x))ans+=t[x];
		return ans;
	}
}BIT;

inline void access(int x,int id){//and make root
	int tmp=null;
	int d=x;
	while(x){
		splay(x);
		t[x].ch[1]=tmp;
		pushup(x);
		int SZ=t[x].sz-t[t[x].ch[1]].sz;
		BIT.add(t[x].col,-SZ);
		//
		BIT.add(id,SZ);
		tmp=x; x=t[x].fa;
	}
	splay(d);
	t[d].paint=id;
	t[d].rev^=1;
}
int anc[N][20];
int hed[N],to[N<<1],nxt[N<<1],ecnt,deg[N];
int dep[N];
inline void adde(int u,int v){
	++ecnt;to[ecnt]=v,nxt[ecnt]=hed[u];hed[u]=ecnt;
}
inline void dfs(int x,int pre){
	dep[x]=dep[pre]+1;
	t[x].fa=pre; anc[x][0]=pre; for(int i=1;1<<i<=n;i++)anc[x][i]=anc[anc[x][i-1]][i-1];
	for(int i=hed[x];i;i=nxt[i]){
		int v=to[i];if(v==pre)continue;
		deg[x]++;
		dfs(v,x);
	}
}
priority_queue<int,vector<int>,greater<int> > heap;

inline int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=18;~i;i--)if(dep[anc[x][i]]>=dep[y])x=anc[x][i];
	if(x==y)return x;
	for(int i=18;~i;i--)if(anc[x][i]^anc[y][i]) x=anc[x][i],y=anc[y][i];
	return anc[x][0];
}
int start[N<<1];
char opt[20];

inline int qry(int x){
	splay(x);
	int sd=BIT.qry(t[x].col-1);
	int ca=lca(start[t[x].col],x);
	int len=dep[start[t[x].col]]+dep[x]-dep[ca]*2+1;
	return sd+len;
}

int main()
{
	cin>>n>>T;
	BIT.set(n+T+1);
	for(int i=1;i<n;i++){
		int u,v;scanf("%d%d",&u,&v);
		adde(u,v);adde(v,u);
	}
	dfs(n,0);
	for(int i=1;i<=n;i++)if(deg[i]==0)heap.push(i);
	int time=0;
	while(!heap.empty()){
		int u=heap.top();heap.pop();
		//cout<<u<<endl;
		t[u].col=++time;
		t[u].sz=1;
		BIT.add(time,1);
		deg[anc[u][0]]--;
		start[time]=u;
		if(u!=n&&!deg[anc[u][0]])heap.push(anc[u][0]);
	}
	int final=n;
	while(T--){
		scanf("%s",opt+1);
		if(opt[1]=='u'){//up
			start[++time]=final;
			int id;scanf("%d",&id);
			final=id;
			access(id,time);
		}
		else if(opt[1]=='c'){//compare
			int x,y;scanf("%d%d",&x,&y);
			printf("%d\n",qry(x)<qry(y)?x:y);
		}
		else {//when
			int x;scanf("%d",&x);
			printf("%d\n",qry(x));
		}
	}
	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值