异或粽子
传送门
做法可以类比超级钢琴,每次贪心取当前最大的一段区间然后将其裂成两个更小的,用可持久化01trie来维护区间
的最优值(即固定左端点),然后对于这些端点的答案用一个堆来维护即可。
代码:
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
typedef long long ll;
const int N=5e5+5,M=N*40;
int n,k;
inline unsigned int read(){
unsigned int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
ll sum[N],a[N];
int rt[N];
namespace trie{
#define lc (son[p][0])
#define rc (son[p][1])
int son[M][2],siz[M],tot=0;
inline void insert(int&tt,int o,ll v){
int p=tt=++tot;
for(ri t,i=31;~i;--i){
lc=son[o][0],rc=son[o][1];
son[p][t=(v>>i)&1]=++tot;
p=son[p][t],o=son[o][t];
siz[p]=siz[o]+1;
}
}
inline ll query(int ql,int qr,ll v){
ll ret=0;
for(ri t,i=31;~i;--i){
t=((v>>i)&1)^1;
if(siz[son[ql][t]]^siz[son[qr][t]])ql=son[ql][t],qr=son[qr][t],ret|=(i^31)?(1<<i):(1ll<<i);
else ql=son[ql][t^1],qr=son[qr][t^1];
}
return ret;
}
#undef lc
#undef rc
}
struct Node{ll v;int l,r,L,R;friend inline bool operator<(const Node&a,const Node&b){return a.v<b.v;}};
priority_queue<Node>q;
tr1::unordered_map<ll,int>mp;
set<int>S[N];
int sig=0;
int main(){
n=read(),k=read();
trie::insert(rt[0],0,0);
for(ri i=1;i<=n;++i){
sum[i]=sum[i-1]^(ll)read(),trie::insert(rt[i],rt[i-1],sum[i]);
if(!mp[sum[i]])mp[sum[i]]=++sig;
S[mp[sum[i]]].insert(i);
}
for(ri i=1;i<=n;++i){
ll tmp=trie::query(rt[i-1],rt[n],sum[i-1]);
q.push((Node){tmp,i,*S[mp[tmp^sum[i-1]]].lower_bound(i),i,n});
}
int l,r,lim,L,R;
ll ans=0,t;
while(k--){
Node tmp=q.top();
q.pop();
l=tmp.l,r=tmp.r,L=tmp.L,R=tmp.R;
ans+=tmp.v;
if(r^L){
t=trie::query(rt[L-1],rt[r-1],sum[l-1]);
q.push((Node){t,l,*S[mp[t^sum[l-1]]].lower_bound(L),L,r-1});
}
if(r^R){
t=trie::query(rt[r],rt[R],sum[l-1]);
q.push((Node){t,l,*S[mp[t^sum[l-1]]].lower_bound(r+1),r+1,R});
}
}
cout<<ans;
return 0;
}
字符串问题
传送门
感觉不是很难的字符串题。。。
显然可以想到用
去过掉
的部分分。
然后剩下的二十分就只需要用一个前缀和优化建图就完了。
代码:
#include<bits/stdc++.h>
#define ri register int
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
inline int read(){
#define gc getchar
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
#undef gc
}
const int N=6e6+5;
vector<pii>e[N];
int A,B,du[N];
int n,len[N];
char s[N];
struct Node{int len,id;friend inline bool operator<(const Node&a,const Node&b){return a.len<b.len;}};
namespace sam{
vector<Node>S1[N],S2[N];
int son[N][26],len[N],link[N],tot,last,pos[N],st[N][20];
inline int build(){return link[++tot]=0,S1[tot].clear(),S2[tot].clear(),len[tot]=0,memset(son[tot],0,sizeof(son[tot])),tot;}
inline void clear(){tot=0,last=build();}
inline void add(int x,int y,int w){e[x].push_back(pii(y,w)),++du[y];}
inline void extend(int x,int id){
int p=last,np=build();
len[pos[id]=last=np]=len[p]+1;
while(p&&!son[p][x])son[p][x]=np,p=link[p];
if(!p){link[np]=1;return;}
int q=son[p][x],nq;
if(len[q]==len[p]+1){link[np]=q;return;}
nq=build(),len[nq]=len[p]+1,memcpy(son[nq],son[q],sizeof(son[q])),link[nq]=link[q],link[q]=link[np]=nq;
while(p&&son[p][x]==q)son[p][x]=nq,p=link[p];
}
inline void init(){
for(ri i=1;i<=tot;++i)st[i][0]=link[i];
for(ri j=1;j<20;++j)for(ri i=1;i<=tot;++i)st[i][j]=st[st[i][j-1]][j-1];
}
inline void update(int id,int l,int r){
int x=pos[r];
for(ri i=19;~i;--i)if(len[st[x][i]]>=r-l+1)x=st[x][i];
id<=A?S1[x].push_back((Node){r-l+1,id}):S2[x].push_back((Node){r-l+1,id});
}
inline void prepare(){
for(ri p1,p2,s1,s2,r1,r2,p=tot;p;--p){
sort(S1[p].begin(),S1[p].end());
sort(S2[p].begin(),S2[p].end());
p1=p2=0,s1=S1[p].size()-1,s2=S2[p].size()-1;
add(A+B+p,A+B+p+tot,0);
if(~s1)add(A+B+p,S1[p][0].id,0);
for(ri i=p1;i<s1;++i)add(S1[p][i].id,S1[p][i+1].id,-S1[p][i].len);
for(ri i=p2,j=p1;i<=s2&&j<=s1;++i){
while(j<=s1&&S2[p][i].len>S1[p][j].len)++j;
if(j>s1)break;
add(S2[p][i].id,S1[p][j].id,0);
}
if(p^1)add(link[p]+A+B+tot,A+B+p,0);
for(ri i=p2;i<=s2;++i)add(S2[p][i].id,A+B+p+tot,0);
}
}
}
inline void topsort(){
static int q[N],hd,tl,cnt;
static ll f[N],val[N],ans;
hd=1,tl=cnt=ans=0;
for(ri i=1;i<=A+B+sam::tot*2;++i){
if(!du[i])q[++tl]=i;
val[i]=f[i]=(i<=A?len[i]:0);
}
while(hd<=tl){
int x=q[hd++];
++cnt,ans=max(ans,f[x]);
for(ri i=0,v;i<e[x].size();++i){
--du[v=e[x][i].fi];
f[v]=max(f[v],f[x]+e[x][i].se+val[v]);
if(!du[v])q[++tl]=v;
}
}
for(ri i=1;i<=A+B+sam::tot*2;++i)if(du[i]){puts("-1");return;}
cout<<ans<<'\n';
}
int main(){
for(ri tt=read();tt;--tt){
for(ri i=1;i<=A+B+sam::tot*2;++i)e[i].clear(),du[i]=len[i]=0;
sam::clear();
scanf("%s",s+1),n=strlen(s+1);
reverse(s+1,s+n+1);
for(ri i=1;i<=n;++i)sam::extend(s[i]-'a',i);
sam::init();
A=read();
for(ri i=1,l,r;i<=A;++i)l=read(),r=read(),sam::update(i,n-r+1,n-l+1),len[i]=r-l+1;
B=read();
for(ri i=1,l,r;i<=B;++i)l=read(),r=read(),sam::update(i+A,n-r+1,n-l+1);
sam::prepare();
for(ri m=read(),u,v;m;--m)u=read(),v=read()+A,sam::add(u,v,0);
topsort();
}
return 0;
}
春节十二响
去nm的春节十二响,直接用
启发式合并+贪心就能
过去。
复杂度参见长链剖分(才不是
呢)可以去掉一个
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
const int N=2e5+5;
typedef long long ll;
vector<int>e[N],tmp;
int n,a[N],fa[N];
multiset<int>S[N];
typedef multiset<int>::iterator It;
vector<It>g;
inline void merge(int x,int y){
if(S[x].size()<S[y].size())swap(S[x],S[y]);
if(!S[y].size())return;
It ia=S[x].end(),ib=S[y].end();
--ia,--ib;
tmp.clear(),g.clear();
while(1){
tmp.push_back(max(*ia,*ib));
g.push_back(ia);
if(ib==S[y].begin())break;
--ia,--ib;
}
for(ri i=0;i<g.size();++i)S[x].erase(g[i]);
for(ri i=0;i<tmp.size();++i)S[x].insert(tmp[i]);
}
void dfs(int p){
for(ri i=0,v;i<e[p].size();++i)dfs(v=e[p][i]),merge(p,v);
S[p].insert(a[p]);
}
int main(){
n=read();
for(ri i=1;i<=n;++i)a[i]=read();
for(ri i=2;i<=n;++i)fa[i]=read(),e[fa[i]].push_back(i);
dfs(1);
ll ans=0;
for(It it=S[1].begin();it!=S[1].end();++it)ans+=*it;
cout<<ans;
return 0;
}