231110校内赛
T1 拼图
首先一点需要明白的是横向移动和纵向移动并无关联
接着我们可以花费 \(\mathcal O (k)\) 的时间来枚举左右最长长度和上下最长长度
我们只需要在两次循环时分别排个序,左右和上下分别排序
对于左右移动时,我们枚举每一个点在最左或最右的情况,计算出当前最小的长度,并更新最小步数
最小长度可以 \(\mathcal O(1)\) 计算,因为排完序后在它的左右的就是移到一段后最远的点
可以自己手模一下
对于上下同理
代码很史,建议自己写,有两个循环其实可以省
#include<bits/stdc++.h>
#define N 100010
using namespace std;
struct node{
int x,y;
}a[N];
int n,h,w,mnl,mnr,ans1,ans2;
long long ans;
bool cmp(node x,node y){
return x.x<y.x;
}
bool cmp1(node x,node y){
return x.y<y.y;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>h>>w>>n;
for(int i = 1;i<=n;i++)
cin>>a[i].x>>a[i].y;
mnl = mnr = 0x3f3f3f3f;
sort(a+1,a+n+1,cmp);
mnl = a[n].x-a[1].x+1;
for(int i = 2;i<=n;i++){
int tmp = h+a[i-1].x-a[i].x+1;
if(mnl>tmp){
ans1 = h-a[i].x+1;
mnl = tmp;
}else if(mnl==tmp)
ans1 = min(ans1,h-a[i].x+1);
}
for(int i = 1;i<n;i++){
int tmp = h+a[i].x-a[i+1].x+1;
if(mnl>tmp){
ans1 = a[i].x;
mnl = tmp;
}else if(mnl==tmp)
ans1 = min(ans1,a[i].x);
}
sort(a+1,a+n+1,cmp1);
mnr = a[n].y-a[1].y+1;
for(int i = 2;i<=n;i++){
int tmp = w+a[i-1].y-a[i].y+1;
if(mnr>tmp){
ans2 = w-a[i].y+1;
mnr = tmp;
}else if(mnr==tmp)
ans2 = min(ans2,w-a[i].y+1);
}
for(int i = 1;i<n;i++){
int tmp = w+a[i].y-a[i+1].y+1;
if(mnr>tmp){
ans2 = a[i].y;
mnr = tmp;
}else if(mnr==tmp)
ans2 = min(ans2,a[i].y);
}
cout<<1ll*mnl*mnr<<" "<<ans1+ans2;
return 0;
}
T2 小凯的疑惑
我也挺疑惑的
临时加的题,专门为某位大神准备的,就不说了
我也没写
T3 时间复杂度
有人乱搞搞到了 \(80\) 分,狠狠羡慕了
对于正解来说其实就是 \(\mathcal O(n\sqrt n)\) 的一个优化
\(\mathcal O(n\sqrt n)\) 就是先处理出假设选整个序列后每一个没有达到颜色要求的点的位置
按照这些点的位置划分为一些区间,然后进行同样步骤递归求解
对于正解来说我们先从两边向中找到一个分割点,区间肯定是一大一小,先处理大区间再处理小区间
处理一个区间时记得先在 \(cnt\) 数组中除去另一个区间的点,最后再加回来
每一次复杂度只有 \(\mathcal O(小区间)\) 的,所以理论上是 \(\mathcal O(n \log n)\) 的
如果没有分割点就统计答案,依然递归实现
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
int n,cnt[N],a[N],b[N],ans;
void dfs(int x,int y){
if(y<x) return ;
int l = x,r = y;
int lim = b[y-x+1];
while(cnt[a[l]]>=lim&&l<r&&cnt[a[r]]>=lim){
l++;r--;
}
if(cnt[a[l]]<lim){
for(int i = x;i<=l;i++) cnt[a[i]]--;
dfs(l+1,y);
for(int i = x;i<l;i++) cnt[a[i]]++;
dfs(x,l-1);
}else if(cnt[a[r]]<lim){
for(int i = r;i<=y;i++) cnt[a[i]]--;
dfs(x,r-1);
for(int i = r+1;i<=y;i++) cnt[a[i]]++;
dfs(r+1,y);
}else{
ans = max(ans,y-x+1);
for(int i = x;i<=y;i++) cnt[a[i]]--;
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i = 1;i<=n;i++){
cin>>a[i];
cnt[a[i]]++;
}
for(int i = 1;i<=n;i++)
cin>>b[i];
dfs(1,n);
cout<<ans;
return 0;
}
T4 一些情报
相当于是支持:断开一条边,查询距离一个点的最远点
不妨设现在要求的点为 \(x\),断开的是 \(y\) 到他父亲的边,我们来考虑三种情况:
- \(x\) 在 \(y\) 的子树内
- \(y\) 在 \(x\) 的子树内
- \(x,y\) 的 \(lca\) 在他们两个点的上方
对于情况 1 ,我们维护一个点在子树内的最长链,次长链,以及 \(x\) 到 \(y\) 的路径上往外延伸的最长路径
对于情况 2 ,我们维护 \(y\) 到 \(x\) 的路径上往外延伸的最长路径(这里不同于情况 1,这里维护的最长路径是到根最长),以及 \(x\) 子树内的最长链, 次长链, 次次长链, 还有 \(x\) 到根路径上往外延伸的最长路径
对于情况 3 ,跟前面两种情况类似,相当于结合起来多考虑几种情况
最长链,次长链,次次长链都可以在 \(\mathcal O(n)\) 的时间内预处理出,往外延伸的最长路径可以通过倍增预处理每次 \(\mathcal O(\log n)\) 的时间内求出
所以总复杂度 \(\mathcal O(n\log n)\)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
const int Maxn=2e5+50;
int n,m,ind,rt=1,powG[50],fa[Maxn][23],dis[Maxn],mxdep[Maxn][3],from[Maxn][2],depfa[Maxn][23],depfa2[Maxn][23],dfn[Maxn],in[Maxn],out[Maxn];
vector<int>edge[Maxn];
inline void dfs(int now,int f){
fa[now][0]=(f?f:now);dis[now]=dis[f]+1;
dfn[now]=++ind;in[now]=dfn[now]+1;
for(int i=1;i<=20;i++){fa[now][i]=fa[fa[now][i-1]][i-1];}
for(int e=edge[now].size()-1;e>=0;e--){
int v=edge[now][e];
if(v==f)continue;
dfs(v,now);
if(mxdep[v][0]+1>mxdep[now][0]){
mxdep[now][2]=mxdep[now][1];
mxdep[now][1]=mxdep[now][0];
from[now][1]=from[now][0];
mxdep[now][0]=mxdep[v][0]+1;
from[now][0]=v;
}else if(mxdep[v][0]+1>mxdep[now][1]){
mxdep[now][2]=mxdep[now][1];
mxdep[now][1]=mxdep[v][0]+1;
from[now][1]=v;
}else if(mxdep[v][0]+1>mxdep[now][2]){
mxdep[now][2]=mxdep[v][0]+1;
}
}
out[now]=ind;
}
inline void dfs2(int now,int f){
if(now!=1){
depfa[now][0]=(from[f][0]==now)?(mxdep[f][1]+1):(mxdep[f][0]+1);
depfa2[now][0]=(from[f][0]==now)?(mxdep[f][1]+dis[f]):(mxdep[f][0]+dis[f]);
}
for(int i=1;i<=20;i++){
depfa[now][i]=max(depfa[now][i-1],depfa[fa[now][i-1]][i-1]+dis[now]-dis[fa[now][i-1]]);
depfa2[now][i]=max(depfa2[now][i-1],depfa2[fa[now][i-1]][i-1]);
}
for(int e=edge[now].size()-1;e>=0;e--){
int v=edge[now][e];
if(v==f)continue;
dfs2(v,now);
#include<bits/stdc++.h>
#define int long long
#define N 200010
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
struct node{
int l,r;
}t[N<<2],ans;
int n,m,cnt,dfncnt,dep[N],f[N<<1][20],fa[N][20],dis[N],dfn[N];
int siz[N],id[N],pos[N<<1],lg[N<<1];
vector<int>g[N];
inline int min(int x,int y){
return (dep[x]<=dep[y])?x:y;
}
inline int lca(int l,int r){
l = dis[l];r = dis[r];
if(l>r) swap(l,r);
int k = lg[r-l+1];
return min(f[l][k],f[r-(1<<k)+1][k]);
}
inline int dist(int x,int y){
int l = lca(x,y);
return dep[x]+dep[y]-2*dep[l];
}
node operator+(node x,node y){
if(!x.l) return y;
if(!y.l) return x;
node tmp;tmp.l = x.l;tmp.r = x.r;
int res = -1,c[4] = {x.l,x.r,y.l,y.r};
sort(c,c+4);
int tot = unique(c,c+4)-c;
for(int i = 0;i<tot;i++){
for(int j = i+1;j<tot;j++){
int idx = dist(c[i],c[j]);
if(idx>res){
res = idx;
tmp.l = c[i];tmp.r = c[j];
}
}
}
return tmp;
}
inline int jump(int x,int y){
for(int i = 17;i>=0;i--)
if((y>>i)&1) x = fa[x][i];
return x;
}
inline void dfs(int x,int father){
fa[x][0] = father;
for(int i = 1;i<=17;i++)
fa[x][i] = fa[fa[x][i-1]][i-1];
dep[x] = dep[father]+1;
pos[++cnt] = x;dis[x] = cnt;
dfn[x] = ++dfncnt;
id[dfncnt] = x;siz[x] = 1;
for(int v : g[x]){
if(v==father) continue;
dfs(v,x);
pos[++cnt] = x;
siz[x]+=siz[v];
}
}
inline void pushup(int p){
t[p] = t[lc]+t[rc];
}
inline void build(int p,int l,int r){
if(l==r){
t[p].l = t[p].r = id[l];
return ;
}
int mid = (l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
inline void query(int p,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
ans = ans+t[p];
return ;
}
int mid = (l+r)>>1;
if(ql<=mid) query(lc,l,mid,ql,qr);
if(qr>mid) query(rc,mid+1,r,ql,qr);
}
inline void init(){
lg[0] = -1;
for(int i = 1;i<=cnt;i++)
lg[i] = lg[i>>1]+1;
for(int i = 1;i<=cnt;i++)
f[i][0] = pos[i];
for(int i = 1;(1<<i)<=cnt;i++)
for(int j = 1;j+(1<<i)-1<=cnt;j++)
f[j][i] = min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
return ;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i = 1;i<n;i++){
int x,y;cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,0);
init();
build(1,1,n);
cin>>m;
int rt = 0;
for(int i = 1;i<=m;i++){
char opt;int x,y;
cin>>opt;
if(opt=='C') cin>>rt;
else{
cin>>x>>y;
int tmp = lca(x,rt);
int len = dep[x]-dep[tmp];
ans.l = ans.r = 0;
int pos = 0;
if(y<=len) pos = jump(x,y-1);
else{
int idx = dep[rt]-dep[tmp]-(y-len);
if(idx<0) pos = 1;
else pos = jump(rt,idx);
}
if(dfn[x]<=dfn[pos]+siz[pos]-1&&dfn[x]>=dfn[pos])
query(1,1,n,dfn[pos],dfn[pos]+siz[pos]-1);
else query(1,1,n,1,dfn[pos]-1),query(1,1,n,dfn[pos]+siz[pos],n);
int res = max(dist(ans.l,x),dist(ans.r,x));
cout<<res<<"\n";
}
}
return 0;
}
梦与现实间挣扎着,所求为何
你可以借走我的文章,但你借不走我的智慧 虽然我是傻逼本文来自博客园,作者:cztq,转载请注明原文链接:https://www.cnblogs.com/cztq/p/17824947.html