T1
唐了
点击查看代码
#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N =1E6+6;const ull B=233;
int len;ull h[N],fh[N],p[N];
ull get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
ull fget(int l,int r)
{
int tl=len-r+1;int tr=len-l+1;
return fh[tr]-fh[tl-1]*p[tr-tl+1];
}
bool check(int i)
{
ull l=fget(1,max(1,i-1));
if(2*i-1>len)
{
if(2*i-len>i-1||i+1>len)return 1;
l=fget(2*i-len,i-1);
ull r=get(i+1,len);
// cout<<2*i-len<<" "<<i-1<<" "<<i+1<<" "<<len<<endl;
// cout<<l<<" "<<r<<endl;
return l==r;
}else
{
if(i==1)return 1;
ull r=get(min(i+1,2*i-1),2*i-1);
// cout<<1<<" "<<max(1,i-1)<<" "<<min(i+1,2*i-1)<<" "<<2*i-1<<endl;
// cout<<l<<" "<<r<<endl;
if(l==r)return check(2*i-1);
else return 0;
}
}
int main()
{
int T;
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>T;
string s;p[0]=1;
for(int i=1;i<=1e6;i++)p[i]=p[i-1]*B;
while(T--)
{
cin>>s;
len=s.size();
for(int i=1;i<=len;i++)
{
h[i]=h[i-1]*B+s[i-1];
}
if(len==1)
{
cout<<1<<endl;
continue;
}
for(int i=1;i<=len;i++)
{
fh[i]=fh[i-1]*B+s[len-i];
// cout<<fh[i]<<endl;
}
// cout<<fget(1,1)<<" "<<get(1,1)<<endl;
for(int i=2;i<=len;i++)
{
if(check(i))
{
cout<<i<<" ";
}
}
// cout<<len;
cout<<endl;
}
return 0;
}
其实还能优化,这个复杂度类似倍增啊
可是到这循环可以做到\(O(N)\)
点击查看代码
#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N =1E6+6;const ull B=233;
int len;ull h[N],fh[N],p[N],is[N];
ull get(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
ull fget(int l,int r)
{
int tl=len-r+1;int tr=len-l+1;
return fh[tr]-fh[tl-1]*p[tr-tl+1];
}
bool check(int i)
{
ull l=fget(1,max(1,i-1));
if(2*i-1>len)
{
if(2*i-len>i-1||i+1>len)return 1;
l=fget(2*i-len,i-1);
ull r=get(i+1,len);
return l==r;
}else
{
if(i==1)return 1;
ull r=get(min(i+1,2*i-1),2*i-1);
if(l==r&&is[2*i-1])return 1;
else return 0;
}
}
int main()
{
int T;
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>T;
string s;p[0]=1;
for(int i=1;i<=1e6;i++)p[i]=p[i-1]*B;
while(T--)
{
cin>>s;
len=s.size();
for(int i=1;i<=len;i++)
{
is[i]=0;
h[i]=h[i-1]*B+s[i-1];
fh[i]=fh[i-1]*B+s[len-i];
}
if(len==1)
{
cout<<1<<endl;
continue;
}
is[len]=1;
for(int i=len-1;i>=1;i--)
{
if(check(i))is[i]=1;
}
for(int i=2;i<=len;i++)
{
if(is[i])cout<<i<<" ";
}
// cout<<len;
cout<<endl;
}
return 0;
}
T2
考虑\(a[1]=1和a[n]=n\)与\(a[1]\ne 1或a[n]\ne n\)以及\(a[i]=i\)的情况
其中\(a[n]=1和a[1]=n\)情况特殊,必须操作\(3\)次
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
#define endl '\n'
#define pb push_back
using namespace std;
const int N = 2e5+5;
int n;
ll a[N];
int main()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
int T;
cin>>T;
while(T--)
{
cin>>n;
bool ok=1;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]!=i)ok=0;
}
if(ok)cout<<0<<endl;
else if(a[1]==1||a[n]==n)cout<<1<<endl;
else
{
if(a[n]!=1||a[1]!=n)
{
ll mx=0;bool ff=0;
for(int i=1;i<=n;i++)
{
if(a[i]==i)
{
if(mx<a[i])
{
ff=1;break;
}
}
mx=max(mx,a[i]);
}
if(ff)cout<<1<<endl;
else cout<<2<<endl;
}
else
{
cout<<3<<endl;
}
}
}
return 0;
}
/*
4
5
2 1 3 5 4
3
1 2 3
7
3 2 1 7 5 6 4
6
1 2 3 4 5 6
*/
T3
回滚莫队,不过\(add\)函数复杂度为\(O(R-L+1)\)的,复杂度太高了
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
#define endl '\n'
#define pb push_back
using namespace std;
const int N = 1e5+5,mod=1e9+7;
int n,m,sq,s[N],st[320],ed[320],B,ans[N];
struct qu
{
int l,r,id,bl;
}q[N];
struct ST
{
int mi[20][N],mx[20][N];
void init()
{
for(int i=1;i<=n;i++)
{
mi[0][i]=mx[0][i]=s[i];
}
mi[0][0]=mi[0][n+1]=1e9;
mx[0][0]=mx[0][n+1]=-1e9;
for(int j=1;j<=18;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
mi[j][i]=min(mi[j-1][i],mi[j-1][i+(1<<j-1)]);
mx[j][i]=max(mx[j-1][i],mx[j-1][i+(1<<j-1)]);
}
}
}
ll qmx(int l,int r)
{
// int ans=0;
// for(int i=l;i<=r;i++)ans=max(ans,s[i]);
// return ans;
if(l>r)swap(l,r);
int k=__lg(r-l+1);
return max(mx[k][l],mx[k][r-(1<<k)+1]);
}
ll qmi(int l,int r)
{
// int ans=1e9;
// for(int i=l;i<=r;i++)ans=min(ans,s[i]);
// return ans;
if(l>r)swap(l,r);
int k=__lg(r-l+1);
return min(mi[k][l],mi[k][r-(1<<k)+1]);
}
}rmq;
bool cmp(qu a,qu b)
{
if(a.bl==b.bl)return a.r<b.r;
return a.l<b.l;
}
ll force(int l,int r)
{
ll ans=0;
for(int i=l;i<=r;i++)
{
for(int j=i;j<=r;j++)
{
// cout<<"***"<<i<<" "<<j<<endl;
// cout<<rmq.qmi(i,j)<<" "<<rmq.qmx(i,j)<<endl;
ans=(ans+rmq.qmi(i,j)*rmq.qmx(i,j)%mod)%mod;
}
}
return ans;
}
ll res;
int L=0,R=0;
void add(int x,bool lef)
{
if(lef)
{
for(int i=L;i<=R;i++)
{
res=(res+rmq.qmi(L,i)*rmq.qmx(L,i)%mod)%mod;
}
}else
{
for(int i=L;i<=R;i++)
{
res=(res+rmq.qmi(i,R)*rmq.qmx(i,R)%mod)%mod;
}
}
}
void solve()
{
for(int i=1,j=1;i<=B;i++)
{
R=ed[i];L=ed[i]+1;
res=0;
while(i==q[j].bl)
{
if(q[j].r-q[j].l<=sq)
{
ans[q[j].id]=force(q[j].l,q[j].r);
j++;
continue;
}
L=ed[i]+1;
while(R<q[j].r)
{
R++;
add(R,0);
}
ll tmp=res;
while(L>q[j].l)add(--L,1);
ans[q[j].id]=res;
res=tmp;
j++;
}
}
}
signed main()
{
speed();
// freopen("sequence2.in","r",stdin);
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>s[i];
}
rmq.init();
sq=sqrt(n);B=n/sq;
// sq=1e9;
for(int i=1;i<=m;i++)
{
cin>>q[i].l>>q[i].r;q[i].id=i;
q[i].bl=(q[i].l-1)/sq+1;
// cout<<solve(L,R)<<endl;
}
for(int i=1;i<=B;i++)
{
st[i]=ed[i-1]+1;ed[i]=st[i]+sq-1;
}
if(ed[B]<n)
{
B++;
st[B]=ed[B-1]+1;ed[B]=n;
}
sort(q+1,q+1+m,cmp);
solve();
for(int i=1;i<=m;i++)
{
cout<<ans[i]<<endl;
}
return 0;
}
/*
5 2
2 4 1 5 3
1 4
3 5
*/
T4 P5443 [APIO2019] 桥梁
暴力分,注意细节,MD本来能拿\(29\)结果爆零了
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define endl '\n'
#define pb push_back
using namespace std;
const int N = 5e4+5,M=1e5+5;
int n,m,fa[N];
vector <pii> edge[N];
struct node
{
int u,v,w,id;
}br[M];
bool cmp(node a,node b)
{
return a.w>b.w;
}
bool cmp2(node a,node b)
{
return a.id<b.id;
}
bool cmp3(node a,node b)
{
return a.u<b.u;
}
inline void add(int u,int v,int w)
{
edge[u].pb({v,w});edge[v].pb({u,w});
}
inline int find(int x)
{
if(fa[x]!=x)fa[x]=find(fa[x]);
return fa[x];
}
inline void kruskal()
{
for(int i=1;i<=n;i++)fa[i]=i,edge[i].clear();
int cnt=0;
sort(br+1,br+1+m,cmp);
for(int i=1;i<=m;i++)
{
if(cnt==n-1)break;
int fu=find(br[i].u),fv=find(br[i].v);
if(fu!=fv)
{
fa[fu]=fv;cnt++;
// cout<<br[i].u<<" "<<br[i].v<<" "<<br[i].w<<endl;
add(br[i].u,br[i].v,br[i].w);
}
}
sort(br+1,br+1+m,cmp2);
}
bool vis[N];
ll ans=0;
inline void dfs(int u,int lim)
{
vis[u]=1;
// cout<<"**"<<u<<endl;
for(auto [to,w]:edge[u])
{
// cout<<to<<" "<<w<<" "<<lim<<endl;
if(!vis[to]&&w>=lim)
{
dfs(to,lim);
}
}
}
struct Tree
{
int l,r,mi;
}st[N*4];
inline void pushup(int rt)
{
st[rt].mi=min(st[lid].mi,st[rid].mi);
}
inline void bt(int rt,int l,int r)
{
st[rt].l=l;st[rt].r=r;
if(l==r)
{
st[rt].mi=br[l].w;
return;
}
int mid=(l+r)>>1;
bt(lid,l,mid);bt(rid,mid+1,r);
pushup(rt);
}
inline void update(int rt,int l,int r,int val)
{
if(l<=st[rt].l&&st[rt].r<=r)
{
st[rt].mi=val;
return;
}
int mid=(st[rt].l+st[rt].r)>>1;
if(l<=mid)update(lid,l,r,val);
if(r>mid)update(rid,l,r,val);
pushup(rt);
}
inline int query(int rt,int l,int r)
{
if(l>r)return 0;
if(l<=st[rt].l&&st[rt].r<=r)
{
return st[rt].mi;
}
int mid=(st[rt].l+st[rt].r)>>1;
int ans=1e9;
if(l<=mid)ans=min(ans,query(lid,l,r));
if(r>mid)ans=min(ans,query(rid,l,r));
return ans;
}
int main()
{
speed();
// freopen("bridge1.in","r",stdin);
// freopen("in.in","r",stdin);
// freopen("out1.out","w",stdout);
cin>>n>>m;
int u,v,w;
bool lian=1;bool ercha=1;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>w;
if(abs(u-v)!=1)lian=0;
if(u!=(i+1)/2||v!=i+1)ercha=0;
br[i]={u,v,w,i};
}int q,op;
// lian=0;
// cout<<"****"<<ercha<<endl;
if(m&&!lian&&!ercha)kruskal();
else if(lian&&!ercha)
{
for(int i=1;i<=m;i++)add(br[i].u,br[i].v,br[i].w);
sort(br+1,br+1+m,cmp3);
bt(1,1,n-1);
}else if(ercha)
{
// cout<<"*********"<<endl;
for(int i=1;i<=m;i++)add(br[i].u,br[i].v,br[i].w);
}
cin>>q;bool has=0;
while(q--)
{
cin>>op;
if(op==1)
{
cin>>u>>w;
br[u].w=w;
if(lian&&!ercha)update(1,u,u,w);
has=1;
}else
{
cin>>u>>w;
// cout<<"&&&"<<u<<" "<<w<<endl;
ans=0;
if(!m)
{
cout<<1<<endl;
continue;
}
if(lian==1&&!ercha)
{
// cout<<"***"<<endl;
int l=1,r=max(u-1,1);
int lans=max(u-1,1)+1,rans=min(u,n-1)-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(query(1,mid,max(u-1,1))>=w)
{
lans=mid;
r=mid-1;
}else l=mid+1;
}
l=min(u,n-1),r=n-1;
while(l<=r)
{
int mid=(l+r)>>1;
// cout<<min(u,n-1)<<" "<<mid<<" "<<query(1,min(u,n-1),mid)<<endl;
if(query(1,min(u,n-1),mid)>=w)
{
rans=mid;
l=mid+1;
}else r=mid-1;
}
// cout<<lans<<" "<<rans<<endl;
if(rans-lans+2)cout<<rans-lans+2<<endl;
else cout<<1<<endl;
continue;
}
if(has)
{
has=0;
if(!ercha)kruskal();
dfs(u,w);
}else
{
dfs(u,w);
}
for(int i=1;i<=n;i++)
{
if(vis[i])ans++,vis[i]&=0;
}
cout<<ans<<endl;
}
}
return 0;
}
正解是可撤销并查集,也是与回滚莫队类似的思想,首先可撤销并查集合并和删除时的顺序必须是对应的类似栈(注意,别再路径压缩了),我们可以给\(q\)个询问分块,标记好时间,对于每一个块,分为\(1\)操作和\(2\)操作两部分,修改操作不超过块长\(B\),所以我们可以把边都按从大到小排序,然后先把未被修改且符合条件的边加入,然后因为修改操作比较少,直接暴力插入即可,类似回滚莫队,插入完计算出一个点以后再删除即可,如何暴力插入,就是遍历要修改的边然后判断符合条件的合并即可
\(ys\)为映射数组,因为修改的是原下表
复杂度分析,块长玄学
每个块处理的复杂度为\(O(m\log m+S^2\log n)\)。
根据实际情况取块大小即可。理论复杂度\(O(q\sqrt q\log m)\)。
可以把\(O(m\log m)\)的排序用归并优化掉\(\log\)。则理论复杂度可以做到\(O(q\sqrt{q\log m})\)
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define endl '\n'
#define pb push_back
using namespace std;
const int N = 1e5+5,B=1024;
int n,m,vis[N],ys[N],ans[N];
struct eg
{
int u,v,w,id;
bool operator < (const eg& A)const
{
return w>A.w;
}
}edge[N];
struct qu
{
int w,id,tim;
bool operator < (const qu& A)const
{
return w>A.w;
}
}q[N];
struct Disjoint_Set
{
int fa[N],sz[N],top,st[N];
void init()
{
top=0;
for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1;
}
int find(int x){if(fa[x]!=x)return find(fa[x]);return fa[x];}//别TM路径压缩
void merge(int u,int v)
{
int fu=find(u),fv=find(v);
if(fu!=fv)
{
if(sz[fu]>sz[fv])swap(fu,fv);
sz[fv]+=sz[fu];fa[fu]=fv;
st[++top]=fu;
}
}
void del(int ls)
{
while(top>ls)
{
int u=st[top--];
sz[fa[u]]-=sz[u];
fa[u]=u;
}
}
}S;
vector <qu> M,Q;
void solve()
{
sort(edge+1,edge+1+m);
sort(Q.begin(),Q.end());
vector <qu> MM;MM.clear();
for(int i=1;i<=m;i++)ys[edge[i].id]=i;
for(auto v:M)vis[v.id]=-1,MM.pb({edge[ys[v.id]].w,v.id,0});//时间为0必然
for(auto v:M)MM.pb(v);
S.init();
int it=1;
for(int i=0;i<Q.size();i++)
{
while(it<=m&&edge[it].w>=Q[i].w)
{
if(!vis[edge[it].id])S.merge(edge[it].u,edge[it].v);
it++;
}
int ls=S.top;
for(auto v:MM)
if(v.tim<=Q[i].tim)vis[v.id]=v.w;//可能有多条相同但权值不同的边
for(auto v:M)
if(vis[v.id]>=Q[i].w)
S.merge(edge[ys[v.id]].u,edge[ys[v.id]].v);
ans[Q[i].tim]=S.sz[S.find(Q[i].id)];
// cout<<S.sz[S.find(Q[i].id)]<<endl;
S.del(ls);
}
for(auto v:M)edge[ys[v.id]].w=v.w,vis[v.id]=0;
M.clear();Q.clear();
}
int main()
{
speed();
// freopen("bridge1.in","r",stdin);
// freopen("in.in","r",stdin);
// freopen("out1.out","w",stdout);
cin>>n>>m;
int u,v,w;
for(int i=1;i<=m;i++)
{
cin>>u>>v>>w;
edge[i]={u,v,w,i};
}
int q;cin>>q;int op;
// cout<<q<<endl;
for(int i=1;i<=q;i++)
{
cin>>op;qu x;
x.tim=i;
if(op==1){cin>>x.id>>x.w;M.pb(x);}
else {cin>>x.id>>x.w;Q.pb(x);}
if(i%B==0)solve();
}
if(q%B)solve();
for(int i=1;i<=q;i++)
{
if(ans[i])
cout<<ans[i]<<endl;
}
return 0;
}