day1训练(省赛前)
考完期中考试的弱鸡补题恢复状态ing.
416div2A.
(水题
#include <bits/stdc++.h> #define ll long long #define s second #define f first #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=1e5+10; using namespace std; int main(){ ll n,m;cin>>n>>m; int cnt1=0;int t=1e5; inc(i,1,t){ if(m<1ll*i*(i+1)){ cnt1=i-1;break; } } int cnt2=0; inc(i,1,t){ if(n<1ll*i*i){ cnt2=i-1;break; } } //cout<<cnt1<<" "<<cnt2<<endl; if(cnt1>=cnt2) cout<<"Vladik"<<endl; else cout<<"Valera"<<endl; return 0; }
416div2B.(水题
#include <bits/stdc++.h> #define ll long long #define s second #define f first #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=1e4+10; using namespace std; int a[MAXN]; int main(){ int n,m;cin>>n>>m; inc(i,1,n) cin>>a[i]; int l,r,x;int cnt,cnt1; inc(i,1,m){ cin>>l>>r>>x; if(x<l||x>r){ cout<<"Yes"<<endl;continue; } int t1=x-l+1;cnt=cnt1=0; inc(j,l,r){ if(a[j]<a[x]) cnt++; if(a[j]==a[x]) cnt1++; } if(cnt+cnt1>=t1&&cnt<t1) puts("Yes"); else puts("No"); } return 0; }
416div2E
题意:http://codeforces.com/contest/811/problem/E
题解:考虑到线段树维护并查集,难点在如何维护合并,考虑到每次合并只需要最左边的一列和最右边的一列 所以我们考虑将左儿子的两端的两列和右儿子两端的两列映射到数组中 然后用并查集维护合并区间的连通性 查询即可。
#include <bits/stdc++.h> #define ll long long #define s second #define f first #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=1e5+10; using namespace std; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } int n,m,q,cnt; int G[11][MAXN],vis[MAXN*10],fa[44]; int a[5]; typedef struct node{ int l,r,ans; int L[11],R[11]; }node; node d[MAXN<<2]; int find1(int x){ if(x==fa[x]) return x; else return fa[x]=find1(fa[x]); } node merge(node x,node y){ node z;z.ans=x.ans+y.ans; inc(i,1,n){ if(vis[x.L[i]]) fa[i]=vis[x.L[i]]; else vis[x.L[i]]=i,fa[i]=i; } inc(i,1,n){ if(vis[x.R[i]]) fa[i+n]=vis[x.R[i]]; else vis[x.R[i]]=n+i,fa[i+n]=n+i; } inc(i,1,n){ if(vis[y.L[i]]) fa[i+2*n]=vis[y.L[i]]; else vis[y.L[i]]=i+2*n,fa[i+2*n]=i+2*n; } inc(i,1,n){ if(vis[y.R[i]]) fa[i+3*n]=vis[y.R[i]]; else vis[y.R[i]]=i+3*n,fa[i+3*n]=i+3*n; } a[1]=x.l;a[2]=x.r;a[3]=y.l;a[4]=y.r; inc(i,1,n){ if(G[i][x.r]!=G[i][y.l]) continue; int t1=find1(n+i); int t2=find1(n*2+i); if(t1==t2) continue; if(t1>t2) swap(t1,t2); z.ans--; fa[t2]=t1; } inc(i,1,n) z.L[i]=(find1(i)-1)*m+x.l; inc(i,1,n){ int t1=find1(3*n+i);int t2=(t1-1)/n+1;int t3=(t1-1)%n+1; z.R[i]=(t3-1)*m+a[t2]; } inc(i,1,n) vis[x.R[i]]=vis[x.L[i]]=vis[y.L[i]]=vis[y.R[i]]=0; z.l=x.l;z.r=y.r; return z; } void built(int rt,int l,int r){ if(l==r){ d[rt].l=d[rt].r=l; d[rt].L[1]=d[rt].R[1]=l;d[rt].ans++; inc(i,2,n){ if(G[i][l]==G[i-1][l]) d[rt].L[i]=d[rt].R[i]=d[rt].L[i-1]; else d[rt].L[i]=d[rt].R[i]=(i-1)*m+l,d[rt].ans++; } return ; } int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); d[rt]=merge(d[rt<<1],d[rt<<1|1]); } bool flag;node ttt; void querty(int rt,int ql,int qr){ if(ql<=d[rt].l&&d[rt].r<=qr){ if(!flag) ttt=d[rt],flag=1; else ttt=merge(ttt,d[rt]); return ; } int mid=(d[rt].l+d[rt].r)>>1; if(ql<=mid) querty(rt<<1,ql,qr); if(qr>mid) querty(rt<<1|1,ql,qr); } int main(){ n=read();m=read();q=read(); inc(i,1,n){ inc(j,1,m) G[i][j]=read(); } built(1,1,m); int l,r; inc(i,1,q){ l=read();r=read(); flag=0;querty(1,l,r); printf("%d\n",ttt.ans); } return 0; }
480div2E
题意:http://codeforces.com/contest/980/problem/E
题解:考虑到数越大对答案的贡献越大 我们可以从大往小考虑 对于每个点 我们来考虑是否应该删除(及这个点目前的深度加上已经保留点的个数是否小于n-k来判断删除的必要性 为什么这么做?可以仔细推一下
#include <bits/stdc++.h> #define ll long long #define s second #define f first #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=1e6+10; using namespace std; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } int n,k; vector<int>vec[MAXN]; vector<int>vv; int d[MAXN<<2],flag[MAXN<<2],dep[MAXN],p[MAXN],fp[MAXN],cnt,num[MAXN],fa[MAXN]; bool vis[MAXN]; void dfs(int v,int pre,int deep){ p[v]=++cnt;fp[cnt]=v;dep[v]=deep+1;num[v]=1; fa[v]=pre; for(int i=0;i<vec[v].size();i++){ int u=vec[v][i]; if(u!=pre){ dfs(u,v,deep+1); num[v]+=num[u]; } } } void push(int x){ if(flag[x]){ flag[x<<1]+=flag[x]; flag[x<<1|1]+=flag[x]; d[x<<1]+=flag[x]; d[x<<1|1]+=flag[x]; flag[x]=0; } } void built(int rt,int l,int r){ if(l==r){ d[rt]=dep[fp[l]];flag[l]=0;return ; } int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); } void update(int rt,int l,int r,int ql,int qr,int vul){ if(ql<=l&&r<=qr){ d[rt]+=vul;flag[rt]+=vul;return ; } int mid=(l+r)>>1; push(rt); if(ql<=mid) update(rt<<1,l,mid,ql,qr,vul); if(qr>mid) update(rt<<1|1,mid+1,r,ql,qr,vul); } int querty(int rt,int l,int r,int t){ if(l==r) return d[rt]; int mid=(l+r)>>1; push(rt); if(t<=mid) querty(rt<<1,l,mid,t); else querty(rt<<1|1,mid+1,r,t); } int main(){ n=read();k=read();int u,v; inc(i,1,n-1){ u=read();v=read(); vec[u].push_back(v); vec[v].push_back(u); } dfs(n,0,0); built(1,1,n); int cnt1=0; for(int i=n;i>=1;i--){ if(vis[i]) continue; int t1=querty(1,1,n,p[i]); if(t1+cnt1<=n-k){ for(int j=i;(vis[j]==0)&&(j!=0);j=fa[j]) update(1,1,n,p[j],p[j]+num[j]-1,-1),vis[j]=1,cnt1++; } else vv.push_back(i); } sort(vv.begin(),vv.end()); for(int i=0;i<vv.size();i++) printf("%d ",vv[i]); printf("\n"); return 0; }