前言
现在我将以最悲伤的心情,记录下我的第一次爆 000 记录。
T1
题面:
(我恨 MLE。)
对于 30%30\%30% 的数据,我们可以用 ST 表然后 O(n2)O(n^2)O(n2) 暴力枚举(我因为开了 long long
,空间复杂度太高然后 MLE 了……)。
对于 100%100\%100% 的数据,考虑使用 O(n)O(n)O(n) 的做法。
我们美剧一个同学,把他作为一段区间中最矮的同学,然后看看以他为最矮的,最远能延伸到哪里。
但是如果按照上面的方法直接暴力做的话,时间复杂度就是 O(n2)O(n^2)O(n2) 的。有没有一种办法可以把里面的循环直接去掉呢?
既然要把里面的循环去掉,就说明查找这个区间所遍历的范围是固定的,那就定个很简单的值:相邻的两个。所以说当相邻的两个同学身高比中间这个同学的身高要高的话,就可以拓宽范围。
但如果我相邻的相邻的那个同学身高也比我高呢?那肯定也要合并进来。按照我们上面的操作,我相邻的同学的相邻的同学应该被囊括进了我相邻的那个同学,也就是说我在把我相邻的那个同学囊括进来的时候,还要把我相邻的相邻的那个同学囊括进来,那什么算法可以干这个事呢?对了:并查集。
因此考虑使用并查集,因为我囊括的同学都是比我身高高的同学,所以我们应该按照身高从高到低的顺序依次用并查集。
然后就是写代码,代码自己看下面:
#include<bits/stdc++.h>
#define code using
#define by namespace
#define plh std
code by plh;
namespace fastio
{
int read()
{
int z=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
{
f=-1;
}
c=getchar();
}
while(c>='0'&&c<='9')
{
z=z*10+c-'0';
c=getchar();
}
return z*f;
}
}
using namespace fastio;
int n,siz[2000006],fa[2000006],id[2000006];
long long a[2000006];
bool vis[2000006];
unsigned long long ans,mn[2000006],mx[2000006];
bool cmp(int x,int y)
{
return a[x]>a[y];
}
int find(int x)
{
if(fa[x]==x)
{
return x;
}
return fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy)
{
fa[fy]=fx;
siz[fx]+=siz[fy];
mn[fx]=min(mn[fx],mn[fy]);
mx[fx]=max(mx[fx],mx[fy]);
ans=max(ans,mx[fx]*mn[fx]*siz[fx]);
}
}
signed main()
{
// freopen("sketch.in", "r", stdin);
// freopen("sketch.out", "w", stdout);
n=read();
// vector<int>fa(n+1),id(n+1);
// vector<long long>a(n+1),siz(n+1);
for(int i=1;i<=n;i++)
{
a[i]=read();
mn[i]=mx[i]=a[i];
siz[i]=1;
ans=max(ans,a[i]*a[i]*1ull);
id[i]=fa[i]=i;
}
sort(id+1,id+n+1,cmp);
for(int i=1;i<=n;i++)
{
vis[id[i]]=1;
if(vis[id[i]-1])
{
merge(id[i],id[i]-1);
}
if(vis[id[i]+1])
{
merge(id[i],id[i]+1);
}
}
cout<<ans;
return 0;
}
T2
题面:
一道很恶心的线段树题。
正解的大致意思就是用一颗线段树来维护已经固定了的点,然后看看每个区间的端点的奇偶性是否相同,如果相同,那就把中间的全填上相同奇偶性的值,如果不同, 那就必须多一个郁闷值了,因为不管你怎么填它都是一样的,所以这种区间就先跳过不填。
这里还要注意一下:根据贪心可以得到:当两端奇偶性相同时,应该从长度最短的区间开始填,直到填不了为止。
剩下的作者也不想写了,因为题目实在是太复杂,代码解释起来也很费力,如果可以,我以后单独开一篇文章讲一讲这题。
代码先放在这:
#include<bits/stdc++.h>
#define int long long
#define code using
#define by namespace
#define plh std
code by plh;
namespace fastio
{
int read()
{
int z=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
{
f=-1;
}
c=getchar();
}
while(c>='0'&&c<='9')
{
z=z*10+c-'0';
c=getchar();
}
return z*f;
}
void write(int x,int k)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x==0)
{
if(!k)
{
putchar('0');
}
return;
}
write(x/10,k+1);
putchar(char(x%10+'0'));
}
}
struct Tree{
int sumlen[1000006],cntlen[1000006];
int lowbit(int x)
{
return x&-x;
}
void add(int x)
{
for(int i=x;i<=1000000;i+=lowbit(i))
{
sumlen[i]+=x;
cntlen[i]++;
}
}
void del(int x)
{
for(int i=x;i<=1000000;i+=lowbit(i))
{
sumlen[i]-=x;
cntlen[i]--;
}
}
pair<int,int> qry(int x)
{
int ans=0,y=0;
for(int i=20;i>=0;i--)
{
if(y+(1<<i)<=1000000&&x>=sumlen[y+(1<<i)])
{
y+=(1<<i);
x-=sumlen[y];
ans+=cntlen[y];
}
}
ans+=x/(y+1);
x%=(y+1);
return {ans,x};
}
}tr[2];
using namespace fastio;
int n,m,q,cnt1,cnt2,a[1000006],t[2];
set<int>s;
void query()
{
if(s.size()==2)
{
if(t[0]>=n||t[1]>=n)
{
write(0,0);
return;
}
write(1,0);
return;
}
int ans=cnt1*2+cnt2;
int st[5],top=0;
if(a[1]==0)
{
auto it=++s.begin();
int len=(*it)-1;
tr[a[0]&1].del(len);
st[++top]=(a[*it]&1);
st[++top]=-len;
ans--;
}
if(a[n]==0)
{
auto it=--s.end();
it--;
int len=n-(*it);
tr[a[*it]&1].del(len);
st[++top]=(a[*it]&1);
st[++top]=len;
ans--;
}
auto it0=tr[0].qry(t[0]),it1=tr[1].qry(t[1]);
ans-=it0.first*2;
ans-=it1.first*2;
while(top)
{
bool fl=false;
if(st[top]<0)
{
fl=true;
st[top]=-st[top];
}
if(st[top-1])
{
if(it1.second>=st[top])
{
it1.second-=st[top];
ans--;
}
}
else
{
if(it0.second>=st[top])
{
it0.second-=st[top];
ans--;
}
}
if(!fl)
{
tr[st[top-1]].add(st[top]);
}
else
{
tr[0].add(st[top]);
}
top-=2;
}
write(ans,0);
}
void push(auto x,auto y)
{
if((*x)+1<(*y))
{
if((*x)==0||(*y)==n+1||(a[*x]&1)==(a[*y]&1))
{
tr[a[*x]&1].add((*y)-(*x)-1);
cnt1++;
}
else
{
cnt2++;
}
}
else
{
if((*x)==0||(*y)==n+1||(a[*x]&1)==(a[*y]&1))
{
return;
}
else
{
cnt2++;
}
}
}
void pop(auto x,auto y)
{
if((*x)+1<(*y))
{
if((*x)==0||(*y)==n+1||(a[*x]&1)==(a[*y]&1))
{
tr[a[*x]&1].del((*y)-(*x)-1);
cnt1--;
}
else
{
cnt2--;
}
}
else
{
if((*x)==0||(*y)==n+1||(a[*x]&1)==(a[*y]&1))
{
return;
}
else
{
cnt2--;
}
}
}
void delet(int x)
{
auto it=s.lower_bound(x);
auto itl=it,itr=it;
itl--,itr++;
pop(itl,it),pop(it,itr);
a[x]=0;
push(itl,itr);
s.erase(it);
}
void adde(int x,int y)
{
auto itr=s.lower_bound(x);
auto itl=itr;
itl--;
pop(itl,itr);
s.insert(x);
a[x]=y;
auto it=s.lower_bound(x);
itl=it,itr=it;
itl--,itr++;
push(itl,it);
push(it,itr);
}
signed main()
{
cin>>n>>m>>q;
s.insert(0),s.insert(n+1);
for(int i=1;i<=n;i++)
{
t[read()&1]++;
}
for(int i=1,x,y;i<=m;i++)
{
x=read(),y=read();
a[x]=y;
s.insert(x);
t[y&1]--;
}
for(auto i=++s.begin(),j=s.begin();i!=s.end();j=i,i++)
{
push(j,i);
}
while(q--)
{
int op=read();
if(op==1)
{
int x=read();
t[a[x]&1]++;
delet(x);
}
else
{
int x=read(),y=read();
adde(x,y);
t[a[x]&1]--;
}
query();
putchar('\n');
}
return 0;
}
T3
题面:
一道水到不能再水的题……(但我还是挂了……)
很简单:枚举一个点 iii 作为起点,然后按照 ddd 的距离跳,看看有多少个 111 在上面,那么其他的 111 就是要删的,然后暴力枚举一下得出答案即可。
时间复杂度:O(d×nd)=O(n)O(d\times\cfrac{n}{d})=O(n)O(d×dn)=O(n)。
考场上写 freopen
不小心写错了,然后就 CE 了……(你问我为什么会 CE,我只能说我没编译……)
T4
题面:
题目很短,但很恶心,这里不多讲(因为这一道题用了七种算法,你让我怎么讲……),以后有时间单独开一篇文章讲一讲。
代码放在这展览一下:
#include<bits/stdc++.h>
#define int long long
#define code using
#define by namespace
#define plh std
code by plh;
const int LIM=100;
const int B=100;
int n,m;
namespace Tree
{
vector<pair<int,int>>e[600006];
void build(int x,int y,int z)
{
e[x].push_back({y,z});
e[y].push_back({x,z});
}
int st[600006][26];//st表
int lg[600006];//log2函数
int siz[300006];//子树大小
int tdfn[300006];//欧拉序
int num=0,dfn[300006];//欧拉序+1
int depth[300006];//深度
int dis[300006];//到根节点的距离
void dfs(int x,int fx)
{
dfn[x]=++num;
depth[x]=depth[fx]+1;
st[num][0]=x;
siz[x]=1;
tdfn[x]=++tdfn[0];
for(auto i:e[x])
{
if(i.first!=fx)
{
dis[i.first]=dis[x]+i.second;
dfs(i.first,x);
st[++num][0]=x;
siz[x]+=siz[i.first];
}
}
}
void st_()
{
for(int i=2;i<=(n<<1);i++)
{
lg[i]=lg[i>>1]+1;
}
dfs(1,0);
for(int i=1;i<=20;i++)
{
for(int j=1;j+(1<<i)-1<=(n<<1);j++)
{
if(depth[st[j][i-1]]<depth[st[j+(1<<i-1)][i-1]])
{
st[j][i]=st[j][i-1];
}
else
{
st[j][i]=st[j+(1<<i-1)][i-1];
}
}
}
}
int lca(int x,int y)
{
x=dfn[x],y=dfn[y];
if(x>y)
{
swap(x,y);
}
int k=lg[y-x+1];
return depth[st[x][k]]<depth[st[y-(1<<k)+1][k]]?st[x][k]:st[y-(1<<k)+1][k];
}
int dist(int x,int y)
{
return dis[x]+dis[y]-dis[lca(x,y)]*2;
}
int isfa(int x,int y)
{
return tdfn[x]<=tdfn[y]&&tdfn[x]+siz[x]-1>=tdfn[y];
}
}
using Tree::dfn;
using Tree::lca;
using Tree::dist;
using Tree::dis;
using Tree::isfa;
namespace VirtualTree
{
int fa[300006];//父亲节点
int son[300006];//链最长的儿子节点
int len[300006];//底下的最长链
int w[300006];//每个点到父亲节点的边权
vector<pair<int,int>>e[300006];//虚树
void dfs(int x,int fx)
{
fa[x]=fx;
son[x]=0;
for(auto i:e[x])
{
if(i.first==fx)
{
continue;
}
w[i.first]=i.second;
dfs(i.first,x);
if(len[i.first]+i.second>=len[son[x]]+w[son[x]])
{
son[x]=i.first;
}
}
len[x]=(son[x]?w[son[x]]+len[son[x]]:0);
}
vector<pair<int,int>> build(vector<int>&v)
{
sort(v.begin(),v.end(),[&](int a,int b)
{
return dfn[a]<dfn[b];
});
vector<int>vv(v.size()+v.size()-1);
int cnt=0;
for(int i=0;i<v.size()-1;i++)
{
vv[cnt++]=lca(v[i],v[i+1]);
}
for(auto i:v)
{
vv[cnt++]=i;
}
sort(vv.begin(),vv.end());
vv.erase(unique(vv.begin(),vv.end()),vv.end());
sort(vv.begin(),vv.end(),[&](int a,int b)
{
return dfn[a]<dfn[b];
});
for(auto i:vv)
{
e[i].clear();
}
static int top=1,stk[300006];
stk[top]=vv[0];
int rt=vv[0];
for(int i=1;i<vv.size();i++)
{
int x=vv[i];
while(top>1&&!isfa(stk[top],x))
{
e[stk[top]].push_back({stk[top-1],dis[stk[top]]-dis[stk[top-1]]});
e[stk[top-1]].push_back({stk[top],dis[stk[top]]-dis[stk[top-1]]});
top--;
}
stk[++top]=x;
}
while(top>1)
{
e[stk[top]].push_back({stk[top-1],dis[stk[top]]-dis[stk[top-1]]});
e[stk[top-1]].push_back({stk[top],dis[stk[top]]-dis[stk[top-1]]});
top--;
}
//下面是贪心
static int dis[300006];
static bool vis[300006];
for(auto i:vv)
{
vis[i]=0;
}
queue<int>q;
q.push(rt);
dis[rt]=0;
vis[rt]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(auto i:e[x])
{
int y=i.first;
int z=i.second;
if(vis[y])
{
continue;
}
vis[y]=1;
dis[y]=dis[x]+z;
q.push(y);
}
}
rt=0;
int mx=-10;
for(auto i:v)
{
if(dis[i]>=mx)
{
mx=dis[i];
rt=i;
}
}
dfs(rt,0);
w[rt]=0;
sort(vv.begin(),vv.end(),[&](int x,int y)->bool
{
if(x==rt)
{
return 1;
}
return len[x]+w[x]>len[y]+w[y];
});
vector<pair<int,int>>ans;
vector<int>tmp;
ans.push_back({rt,0ll});
for(auto i:vv)
{
vis[i]=0;
}
int s=0;
for(auto i:vv)
{
if(ans.size()>=LIM)
{
break;
}
if(vis[i])
{
tmp.push_back(i);
continue;
}
int u=i;
s+=len[i]+w[i];
vis[i]=1;
while(son[u])
{
u=son[u];
vis[u]=1;
}
ans.push_back({u,s});
}
cnt=0;
while(ans.size()<v.size()&&ans.size()<LIM)
{
ans.push_back({tmp[cnt++],s});
}
return ans;
}
}
vector<pair<int,int>> merge(vector<pair<int,int>>&x,vector<pair<int,int>>&y)
{
vector<int>a(x.size()+y.size());
for(int i=0;i<x.size();i++)
{
a[i]=x[i].first;
}
for(int i=0;i<y.size();i++)
{
a[i+x.size()]=y[i].first;
}
return VirtualTree::build(a);
}
vector<pair<int,int>>st[3006][26];
int lg[300006],a[300006];
int zb(int x)
{
return (x-1)/B+1;
}
int query(int l,int r,int k)
{
int ll=zb(l),rr=zb(r);
static int stk[300006];
int top=0;
if(ll==rr)
{
for(int i=l;i<=r;i++)
{
stk[++top]=a[i];
}
}
else
{
for(int i=l;i<=ll*B;i++)
{
stk[++top]=a[i];
}
for(int i=(rr-1)*B+1;i<=r;i++)
{
stk[++top]=a[i];
}
l=ll+1,r=rr-1;
if(l<=r)
{
int k=lg[r-l+1];
vector<pair<int,int>>lv=st[l][k];
vector<pair<int,int>>rv=st[r-(1<<k)+1][k];
for(auto i:lv)
{
stk[++top]=i.first;
}
for(auto i:rv)
{
stk[++top]=i.first;
}
}
}
vector<int>v(stk+1,stk+1+top);
vector<pair<int,int>>ans=VirtualTree::build(v);
return ans[k-1].second;
}
void decode(int &l,int &r,int &k,int lstans,int testop)
{
lstans%=19260817;
if(testop)
{
l^=lstans;
l=(l%n+n)%n+1;
r^=lstans;
r=(r%n+n)%n+1;
if(l>r)
{
swap(l, r);
}
k^=lstans;
k=(k%min(r-l+1,100ll))+1;
}
}
int op;
signed main()
{
int c;
cin>>c;
cin>>op>>n;
for(int i=1,x,y,z;i<n;i++)
{
cin>>x>>y>>z;
Tree::build(x,y,z);
}
Tree::st_();
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=2;i<=n;i++)
{
lg[i]=lg[i>>1]+1;
}
int m=zb(n);
for(int i=1;i<=n;i+=B)
{
int l=i,r=min(i+B-1,n);
vector<int>vec(a+l,a+r+1);
st[zb(i)][0]=VirtualTree::build(vec);
}
for(int i=1;i<=20;i++)
{
for(int j=1;j+(1<<i)<=m;j++)
{
st[j][i]=merge(st[j][i-1],st[j+(1<<i-1)][i-1]);
}
}
int q;
cin>>q;
int lstans=0;
while(q--)
{
int l,r,k;
cin>>l>>r>>k;
decode(l,r,k,lstans,op);
lstans=query(l,r,k);
cout<<lstans<<endl;
}
return 0;
}
其他的话
你可能觉得这篇文章好像就这样被我水过去了(实际上确实如此),但我是真的不想再提及这件事,因此每道题写的比较简短,我也没想过这篇文章的质量分能有多高。(而且,水的题不也很水吗?难的题不也很难吗?)
还有就是上面我的所有承诺必定会实现,请各位读者帮忙监督我(不然我怕我会忘)。