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]);
}
}