Codeforces Round #805-#808【部分题解】

Codeforces Round #805

        G. Passable Paths

        LCA,先预处理每个结点的深度,查询时既需要枚举结点,然后判断get_dis(z,x)+get_dis(x,y)==get_dis(z,y),这说明z,x,y在一条链上,x在中间,或者x或y在中间,其他出现其他情况说明三个点不在链上。

#include <bits/stdc++.h>
using namespace std;
#define sc(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define ll long long
#define pb push_back
const int Max=2e5+5;
vector<int>mp[Max];
int depth[Max],fa[Max][25],dis[Max];
int n;
void bfs(int x){
    int start=x;
    queue<int>q;
    q.push(start);
    int nx;
    depth[x]=1;
    while(!q.empty()){
        start=q.front();
        q.pop();
        for(auto v:mp[start]){
            if(depth[v]==-1){
                depth[v]=depth[start]+1;
                dis[v]=dis[start]+1;
                q.push(v);
                fa[v][0] = start;
                for (int k = 1; k <= 20; ++k) {
                    fa[v][k] = fa[fa[v][k - 1]][k - 1];
                }
            }
        }
    }
}
int lca(int a, int b) {/*倍增求lca(最近公共祖先)*/
    if (depth[a] < depth[b]) swap(a, b);
    for (int i = 20; i >= 0; --i) {
        if (depth[fa[a][i]] >= depth[b]) a = fa[a][i];
    }
    if (a == b) return a;
    for (int i = 20; i >= 0; --i) {
        if (fa[a][i] != fa[b][i]) {
            a = fa[a][i];
            b = fa[b][i];
        }
    }
    return fa[a][0];
}
int get_dis(int x,int y){
    return dis[x]+dis[y]-2*dis[lca(x,y)];
}
int main(){
    sc(n);
    for(int i=1;i<=n-1;i++){
        int u,v;
        sc(u);sc(v);
        mp[u].pb(v);
        mp[v].pb(u);
    }
    for(int i=1;i<=n;i++) depth[i]=-1;
    bfs(1);
    int t;sc(t);
    while(t--){
        int q;sc(q);
        if(q==1||q==2){
            for(int i=1;i<=q;i++){
                int x;sc(x);
            }
            printf("YES\n");
        }else{
            int x,y;
            sc(x);sc(y);
            bool flag=true;
            for(int i=3;i<=q;i++){
                int z;sc(z);
                if(get_dis(x,z)+get_dis(z,y)==get_dis(x,y)) continue;
                if(get_dis(z,x)+get_dis(x,y)==get_dis(z,y)){
                    x=z;continue;
                }
                if(get_dis(x,y)+get_dis(y,z)==get_dis(x,z)){
                    y=z;continue;
                }
                flag=false;
            }
            if(flag) printf("YES\n");
            else printf("NO\n");
        }
    }
}

Codeforces Round #807

        E. Mark and Professor Koro

        线段树+二分   题解来源:Codeforces Round #807 (Div. 2) A~E - 知乎 (zhihu.com)

    

 

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
//#define rep(i,a,b) for(int i=a;i<=b;i++)
//#define rep2(i,a,b) for(int i=a;i>=b;i--)
///* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define sc(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define ll long long
#define pb push_back
typedef pair<int,int>PII;
const int Max=2e5+200;
const ll INF=1e15+5;
int a[Max];
int num[Max];

int m,n;
ll tree[1000005],flag[1000005];
void buildtree(int node,int start,int end){
	if(start==end){
		tree[node]=num[start];
		return ;
	}
	int mid=(start+end)/2;
	int Lchild=node*2;
	int Rchild=node*2+1;
	buildtree(Lchild,start,mid);
	buildtree(Rchild,mid+1,end);
	tree[node]=tree[Lchild]+tree[Rchild];
}
void pushdown(int node,int Lchild,int Rchild){
	if(flag[node]){
		int mid=(Lchild+Rchild)/2;
		tree[node*2]+=flag[node]*(mid-Lchild+1);
		tree[node*2+1]+=flag[node]*(Rchild-mid);
		flag[node*2]+=flag[node];
		flag[node*2+1]+=flag[node];
		flag[node]=0;
	}
}
 
long long int add(int node,int start,int end,int L,int R){
//	cout<<start<<' '<<end<<' '<<L<<' '<<R<<endl;
	if(end<L||start>R) return 0;
	if(start>=L&&end<=R){
		return tree[node];
	}
	pushdown(node,start,end);
	//cout<<start<<' '<<end<<' '<<L<<' '<<R<<endl;
	int mid=(start+end)/2;
	long long int Lchild=0,Rchild=0;
	Lchild=add(node*2,start,mid,L,R);
	Rchild=add(node*2+1,mid+1,end,L,R);
	return Lchild+Rchild;
}
void update(int node,int start,int end,int L,int R,int num){
	//cout<<start<<' '<<end<<endl;
	if(end<L||start>R) return ;
	if(start>=L&&end<=R){
		flag[node]+=num;
		tree[node]+=num*(end-start+1);
		return ;
	}
	pushdown(node,start,end);
	int mid=(start+end)/2;
	if(mid>=L) update(node*2,start,mid,L,R,num);
	if(R>=mid+1) update(node*2+1,mid+1,end,L,R,num);
	tree[node]=tree[node*2]+tree[node*2+1];
}//重要 
//if(end<L||start>R) return ;
/*if(mid>=L) update(node*2,start,mid,L,R,num);
	if(R>=mid+1) update(node*2+1,mid+1,end,L,R,num);*/
//两者选一
int find(int node,int l,int r,int x){
	if(tree[node]==r-l+1) return 0;
	// cout<<l<<' '<<r<<"---\n";
	if(l==r){
		// cout<<tree[node]<<' '<<l<<' '<<r<<"****\n";
		return l;
	}
	pushdown(node,l,r);
	int mid=(l+r)/2;
	// cout<<tree[node*2+1]<<"++++\n";
	if(tree[node*2]==mid-l+1||x>mid) return find(node*2+1,mid+1,r,x);
	int ret=find(node*2,l,mid,x);
	if(ret) return ret;
	else return find(node*2+1,mid+1,r,x);
}
int find_sub(int node,int l,int r,int x){
	if(tree[node]==0) return 0;
	// cout<<l<<' '<<r<<"---\n";
	if(l==r){
		return l;
	}
	pushdown(node,l,r);
	int mid=(l+r)/2;
	// cout<<tree[node*2+1]<<"++++\n";
	if(tree[node*2]==0||x>mid) return find_sub(node*2+1,mid+1,r,x);
	int ret=find_sub(node*2,l,mid,x);
	if(ret) return ret;
	else return find_sub(node*2+1,mid+1,r,x);
}
void Add(int x){
	int l=find(1,1,Max-1,x);
	if(l>x) update(1,1,Max-1,x,l-1,-1);
	update(1,1,Max-1,l,l,1);
	// cout<<l<<"----\n";/
}
void Sub(int x){
	int l=find_sub(1,1,Max-1,x);
	if(l>x) update(1,1,Max-1,x,l-1,1);
	update(1,1,Max-1,l,l,-1);
	// cout<<l<<"----\n";
}
int query(int node,int l,int r){
	if(l==r) return l;
	pushdown(node,l,r);
	int mid=(l+r)/2;
	if(tree[node*2+1]){
		return query(node*2+1,mid+1,r);
	}else return query(node*2,l,mid);
}

int main(){
	int q;
	sc(n);sc(q);
	for(int i=1;i<=n;i++) sc(a[i]),num[a[i]]++;
	for(int i=1;i<Max-1;i++){
		num[i+1]+=num[i]/2;
		num[i]%=2;
	}
	// cout<<num[1]<<"__\n";
	buildtree(1,1,Max-1);
	// cout<<add(1,1,Max-1,1,1)<<"---+----\n";
	// Add(1);
	// Sub(1);
	while(q--){
		int k,l;
		sc(k);sc(l);
		Add(l);
		Sub(a[k]);
		a[k]=l;
		printf("%d\n",query(1,1,Max-1));
	}
}

Codeforces Round #808

        C. Doremy's IQ

        如果一开始跳过的话,是可以参加后面的比赛的,而我们通过 q=q-1 方式参加的比赛最多是 q 次,最后的最好结果就是把 q 正好全部花光,同时尽可能参加比赛,所以重点就是在什么时候选择参加比赛。

        可以倒着来看,如果当前位置是 qnow<ai ,可以在当前位置进行 qnow=qnow+1 ,这样子我们不用考虑后面是不是需要取,因为我们当前维护的值 qnow 已经是最优情况下增加的 qnow 了。

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
//#define rep(i,a,b) for(int i=a;i<=b;i++)
//#define rep2(i,a,b) for(int i=a;i>=b;i--)
///* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define sc(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define ll long long
#define pb push_back
typedef pair<int,int>PII;
const int Max=1e6+5;
const ll INF=1e15+5;
int a[Max];
int mina[Max];
queue<int>q;
int main(){
	int t;sc(t);
	while(t--){
		int n,q;
		sc(n);sc(q);
		for(int i=1;i<=n;i++){
			sc(a[i]);
		}
		mina[n]=1;
		for(int i=n-1;i>=1;i--){
			mina[i]=mina[i+1];
			if(a[i]>mina[i]) mina[i]++;
		}
		for(int i=1;i<=n;i++){
			if(a[i]<=q) printf("1");
			else{
				// cout<<mina[i+1]<<"---\n"
				if(q>=mina[i]) q--,printf("1");
				else printf("0");
			}
		}
		printf("\n");
	}
}

        D. Difference Array

        题目给出a数组,得到b数组,b是a的差分数组,加上a数组的和不超过500000,故a数组最多有sqrt(500000)个不同的数,差分之后会出现很多的0,我只需要操作不等于的部分数组就可以了。

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
//#define rep(i,a,b) for(int i=a;i<=b;i++)
//#define rep2(i,a,b) for(int i=a;i>=b;i--)
///* run this program using the console pauser or add your own getch, system("pause") or input loop */
#define sc(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define ll long long
#define pb push_back
typedef pair<int,int>PII;
const int Max=1e6+5;
const ll INF=1e15+5;
int a[Max];
int mina[Max];
queue<int>q;
int main(){
	int t;sc(t);
	while(t--){
		int n;sc(n);
		for(int i=1;i<=n;i++) sc(a[i]);
		int num=0,ans=n;
		int tmp=1;
		while(n>1){
			for(int i=max(tmp,1);i<n;i++){
				a[i]=a[i+1]-a[i];
				// cout<<a[i]<<' ';
			}
			// cout<<endl;
			n--;
			sort(a+tmp,a+n+1);
			tmp=upper_bound(a+1,a+n+1,0)-(a+1);
			// cout<<tmp<<' '<<n<<"--\n";
			if(tmp==n-1){
				break;
			}
		}
		printf("%d\n",a[n]);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瘾ิۣۖิۣۖิۣۖิꦿ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值