@Cyani
2019-03-23T09:17:43.000000Z
字数 34750
阅读 677
利用了ull能承受18次10^18级别的数相加的性质。理论上支持最多只有 。否则需要及时取模
#void dft(poly &A,int n){
static ll W[N<<1],*H[30],*las=W,mx=0;
for(;mx<n;mx++){
H[mx]=las;ll w=1,wn=power(g,(mod-1)>>(mx+1));
REP(i,1<<mx)*las++=w,w=w*wn%mod;
}
static ll a[N];A.resize(1<<n);
for(int i=0,j=0;i<(1<<n);++i){
a[i]=A[j];
for(int k=1<<(n-1);(j^=k)<k;k>>=1);
}
for(int k=0,d=1;k<n;k++,d<<=1)
for(int i=0;i<(1<<n);i+=d<<1){
ll *l=a+i,*r=a+i+d,*w=H[k],t;
for(int j=0;j<d;++j,++l,++r){
t=(*w++)*(*r)%mod;//t=(*w++)*(*r%mod)%mod;
*r=*l+mod-t,*l+=t;
}
}
REP(i,1<<n)A[i]=a[i]%mod;
}
注意🐮迭之前之后都需要resize
const int mod=998244353;
namespace Poly{
const int N=(1<<20)+5,g=3;
inline int power(int x,int p){
int res=1;
for(;p;p>>=1,x=(ll)x*x%mod)
if(p&1)res=(ll)res*x%mod;
return res;
}
inline int fix(const int x){
return x>=mod?x-mod:x;
}
void dft(poly &A,int n){
static ull W[N<<1],*H[30],*las=W,mx=0;
for(;mx<n;mx++){
H[mx]=las;ull w=1,wn=power(g,(mod-1)>>(mx+1));
REP(i,1<<n)*las++=w,w=w*wn%mod;
}
if(A.size()!=(1<<n))A.resize(1<<n);
static ull a[N];
for(int i=0,j=0;i<(1<<n);++i){
a[i]=A[j];
for(int k=1<<(n-1);(j^=k)<k;k>>=1);
}
for(int k=0,d=1;k<n;k++,d<<=1)
for(int i=0;i<(1<<n);i+=(d<<1)){
ull *l=a+i,*r=a+i+d,*w=H[k],t;
for(int j=0;j<d;j++,l++,r++){
t=(*r)*(*w++)%mod;
*r=*l+mod-t,*l+=t;
}
}
REP(i,1<<n)A[i]=a[i]%mod;
}
void idft(poly &a,int n){
a.resize(1<<n),reverse(a.begin()+1,a.end());
dft(a,n);int inv=power(1<<n,mod-2);
REP(i,1<<n)a[i]=(ll)a[i]*inv%mod;
}
poly FIX(poly a){
while(!a.empty()&&!a.back())a.pop_back();
return a;
}
poly add(poly a,poly b,int op=0){
a.resize(max(a.size(),b.size()));
REP(i,b.size())a[i]=fix(op?a[i]+mod-b[i]:a[i]+b[i]);
return FIX(a);
}
poly mul(poly a,poly b,int t=1){
if(t==1&&a.size()+b.size()<=24){
poly c(a.size()+b.size(),0);
REP(i,a.size())REP(j,b.size())
c[i+j]=(c[i+j]+(ll)a[i]*b[j])%mod;
return FIX(c);
}
int n=1,aim=a.size()*t+b.size();
while((1<<n)<=aim)n++;
dft(a,n),dft(b,n);
if(t==1)REP(i,1<<n)a[i]=(ll)a[i]*b[i]%mod;
else REP(i,1<<n)a[i]=(ll)a[i]*a[i]%mod*b[i]%mod;
idft(a,n),a.resize(aim);
return FIX(a);
}
poly mul(poly a,int b){
REP(i,a.size())a[i]=(ll)a[i]*b%mod;
return FIX(a);
}
poly inv(poly a,int n){ //a[0] != 0
a.resize(n);poly b;
if(n==1){
b.pb(power(a[0],mod-2));
return b;
}
b=inv(a,n+1>>1);
b=add(mul(b,2),mul(b,a,2),1);
return b.resize(n),b;
}
poly Der(poly a){
REP(i,a.size()-1)a[i]=(ll)(i+1)*a[i+1]%mod;
return a.pop_back(),a;
}
poly Int(poly a){
static int inv[N];inv[1]=1;a.pb(0);
rep(i,2,a.size())inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
per(i,a.size()-1,1)a[i]=(ll)a[i-1]*inv[i]%mod;
return a[0]=0,a;
}
poly Ln(poly a,int n){ //a[0] = 1
a=mul(Der(a),inv(a,n)),a.resize(n-1);
return FIX(Int(a));
}
poly Exp(poly a,int n){ //a[0] = 0
a.resize(n);poly b,one(1,1);
if(n==1)return one;
b=Exp(a,n+1>>1);
b=mul(b,add(add(a,Ln(b,n),1),one));
return b.resize(n),b;
}
poly Div(poly a,poly b){
poly c;int n=a.size()-1,m=b.size()-1;
if(n<m)return c;
reverse(a.begin(),a.end());a.resize(n-m+1);
reverse(b.begin(),b.end());b.resize(n-m+1);
c=mul(a,inv(b,n-m+1));c.resize(n-m+1);
return reverse(c.begin(),c.end()),c;
}
poly Mod(poly a,poly b){
return FIX(add(a,mul(Div(a,b),b),1));
}
inline int chk(int x){
return power(x,(mod-1)/2)==1;
}
inline int R(){return rand()%mod;}
inline pii mul(pii a,pii b,int w){
return mp(((ll)a.fi*b.fi+(ll)a.se*b.se%mod*w)%mod,
((ll)a.fi*b.se+(ll)a.se*b.fi)%mod);
}
inline int Sqrt(int x){
if(!chk(x))return -1;
int a=R();while(chk(((ll)a*a-x+mod)%mod))a=R();
int w=((ll)a*a-x+mod)%mod,p=(mod+1)/2;
pii res=mp(1,0),t=mp(a,1);
for(;p;p>>=1,t=mul(t,t,w))
if(p&1)res=mul(res,t,w);
assert(!res.se);
return min(res.fi,mod-res.fi);
}
poly Sqrt(poly a,int n){
if(n==1){
poly b(1,Sqrt(a[0]));
return b;
}
a.resize(n);poly b=Sqrt(a,n+1>>1);
b=mul(add(b,mul(a,inv(b,n))),(mod+1)/2);
return b.resize(n),b;
}
poly fastpow(poly a,ll k,int n) {
a.resize(n),a=FIX(a);
if(!a.size())return a;
int st=0,base=0;while(!a[st])++st;
if(st*k>=n)return a.resize(0),a;
REP(i,a.size()-st)a[i]=a[i+st];
if(st)a.resize(a.size()-st);
base=a[0];ll inv=power(base,mod-2);
REP(i,a.size())a[i]=a[i]*inv%mod;
a=FIX(Exp(mul(Ln(a, n),k%mod),n));;
if(st){
reverse(a.begin(),a.end());
a.resize(a.size()+st*k);
reverse(a.begin(),a.end());
a.resize(n),a=FIX(a);
}
base=power(base,k);
REP(i,a.size())a[i]=(ll)a[i]*base%mod;
return FIX(a);
}
#define lc (o<<1)
#define rc (o<<1|1)
#define mid ((l+r)>>1)
poly owo[N<<1];
void Qinit(int o,int l,int r,vi &x){
if(l==r){
owo[o].resize(2);
owo[o][1]=1,owo[o][0]=mod-x[l];
return;
}
Qinit(lc,l,mid,x),Qinit(rc,mid+1,r,x);
if(o>=2)owo[o]=mul(owo[lc],owo[rc]);
}
void Q(int o,int l,int r,poly f,vi &y){
if(l==r){y[l]=(f.empty()?0:f[0]);return;}
Q(lc,l,mid,Mod(f,owo[lc]),y);
Q(rc,mid+1,r,Mod(f,owo[rc]),y);
}
void Q(int n,int m,poly f,vi &x,vi &y){ //初始化大小!
Qinit(1,0,m-1,x),Q(1,0,m-1,f,y);
}
poly ovo[N<<1];
void Cinit(int o,int l,int r,vi &x){
if(l==r){
ovo[o].resize(2);
ovo[o][1]=1,ovo[o][0]=mod-x[l];
return;
}
Cinit(lc,l,mid,x),Cinit(rc,mid+1,r,x);
ovo[o]=mul(ovo[lc],ovo[rc]);
}
poly C(int o,int l,int r,vi &z){
if(l==r){
poly res(1,z[l]);
return res;
}
return add(mul(C(lc,l,mid,z),ovo[rc]),
mul(C(rc,mid+1,r,z),ovo[lc]));
}
poly C(int n,vi &x,vi &y){ //初始化大小!
Cinit(1,0,n-1,x);
poly M=Der(ovo[1]),z(n,0);
Q(n,n,M,x,z);
REP(i,n)z[i]=(ll)y[i]*power(z[i],mod-2)%mod;
poly res=C(1,0,n-1,z);
return res.resize(n),res;
}
#undef lc
#undef rc
#undef mid
}
using namespace Poly;
玄学方法可以优化到4次dft,不过似乎只快了20%
const int mod=1000000007;
const int N=200005,M=(1<<15);
const ld PI=acos(-1);
struct C{
ld r,i;
inline friend C operator + (const C &a,const C &b){
return (C){a.r+b.r,a.i+b.i};
}
inline friend C operator - (const C &a,const C &b){
return (C){a.r-b.r,a.i-b.i};
}
inline friend C operator * (const C &a,const C &b){
return (C){a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r};
}
inline friend C operator / (const C &a,const ld &b){
return (C){a.r/b,a.i/b};
}
inline C rev(){
return (C){r,-i};
}
};
const C owo1=(C){0.5,0},owo2=(C){0,-0.5},I=(C){0,1};
namespace Poly{
const int N=(1<<19)+5;
poly naive_mul(const poly &A,const poly &B){
poly C(A.size()+B.size()-1,0);
REP(i,A.size())REP(j,B.size())
C[i+j]=(C[i+j]+(ll)A[i]*B[j])%mod;
return C;
}
void dft(C *a,int n){
static C W[N<<1],*H[30],*las=W;
static int R[N],mx=0;
for(;mx<n;++mx){
H[mx]=las;int m=(1<<(mx+1));
REP(i,1<<mx)*las++=(C){cos(2*PI*i/m),sin(2*PI*i/m)};
}
REP(i,1<<n){
R[i]=(i&1?R[i^1]|1<<(n-1):R[i>>1]>>1);
if(i<R[i])swap(a[i],a[R[i]]);
}
for(int k=0,d=1;k<n;++k,d<<=1)
for(int i=0;i<(1<<n);i+=(d<<1)){
C *l=a+i,*r=a+i+d,*w=H[k],x,y;
for(int j=0;j<d;++j,++l,++r){
x=*l,y=(*r)*(*w++);
*l=x+y,*r=x-y;
}
}
}
void idft(C *a,int n){
//reverse(a+1,a+(1<<n));
dft(a,n);int m=1<<n;
REP(i,m)a[i]=a[i]/m;
}
poly mul(const poly &A,const poly &B){
int aim=(A.size()+B.size()-1),n=1;
if(aim<=32)return naive_mul(A,B);
while((1<<n)<=aim)++n;
C *a=new C[1<<n],*b=new C[1<<n];
C *c=new C[1<<n],*d=new C[1<<n];
REP(i,1<<n){
if(i<A.size())a[i]=(C){ld(A[i]>>15),ld(A[i]&(M-1))};
else a[i]=(C){0,0};
if(i<B.size())b[i]=(C){ld(B[i]>>15),ld(B[i]&(M-1))};
else b[i]=(C){0,0};
}
dft(a,n),dft(b,n);
REP(i,1<<n)c[i]=a[i],d[i]=b[i];
REP(i,1<<n){
int j=(!i?0:(1<<n)-i);
static C a1,a2,b1,b2;
a1=owo1*(c[i]+c[j].rev());
a2=owo2*(c[i]-c[j].rev());
b1=owo1*(d[i]+d[j].rev());
b2=owo2*(d[i]-d[j].rev());
a[j]=a1*b1+I*a1*b2;
b[j]=a2*b1+I*a2*b2;
}
idft(a,n),idft(b,n);
poly C(aim,0);
REP(i,aim){
int a1=(ll)(a[i].r+0.5)%mod;
int a2=(ll)(a[i].i+0.5)%mod;
int b1=(ll)(b[i].r+0.5)%mod;
int b2=(ll)(b[i].i+0.5)%mod;
C[i]=(((ll)a1<<30)+((ll)a2<<15)+((ll)b1<<15)+b2)%mod;
}
delete [] a;
delete [] b;
delete [] c;
delete [] d;
return C;
}
}
维护子树信息。注意虚实边切换对答案的影响
共价大爷游长沙
const int N=500005;
int t[N][2],fa[N],rev[N];
ui s[N],w[N],is[N];
inline int isr(int x){
return t[fa[x]][0]!=x&&t[fa[x]][1]!=x;
}
inline void up(int x){
s[x]=s[t[x][0]]^s[t[x][1]]^is[x]^w[x];
}
inline void Rev(int x){
if(!x)return;swap(t[x][0],t[x][1]),rev[x]^=1;
}
inline void down(int x){
if(rev[x])Rev(t[x][0]),Rev(t[x][1]),rev[x]=0;
}
#define B(x) (t[fa[x]][1]==x)
inline void rot(int x){
int y=fa[x],z=fa[y],f=B(x);
fa[t[y][f]=t[x][f^1]]=y;
if(!isr(y))t[z][B(y)]=x;fa[x]=z;
fa[t[x][f^1]=y]=x,up(y),up(x);
}
inline void push(int x){
if(!isr(x))push(fa[x]);down(x);
}
inline void spl(int x){
push(x);
for (;!isr(x);rot(x)){
if(!isr(fa[x]))rot(B(x)^B(fa[x])?x:fa[x]);
}
}
inline void access(int x){
int y=0;
while(x){
spl(x),is[x]^=s[t[x][1]],is[x]^=s[t[x][1]=y],up(x);
y=x,x=fa[x];
}
}
inline void evert(int x){
access(x),spl(x),Rev(x);
}
inline void cut(int x,int y){
evert(x),access(y),spl(y);
t[y][0]=fa[x]=0,up(y);
}
inline void link(int x,int y){
evert(x),access(y),spl(y);
fa[x]=y,is[y]^=s[x],up(y);
}
inline void upd(int x,ui y){
access(x),spl(x),w[x]^=y,up(x);
}
inline ui qry(int x,int y){
return evert(x),access(y),spl(y),s[x];
}
维护凸包(最好离线CDQ解决..)注意维护点的偏序关系。
namespace Cov {
/*
实现接口:
init, 初始化
insert(point p), 插入点p,并动态维护上凸包
query(point p), 询问凸包上与其点积最大的点
*/
const int N = 250005;
int lc[N], rc[N], sz[N], fix[N];
int pre[N], suf[N];
point key[N];
int tot, rt;
inline int nw(point p) {
int o = ++ tot;
key[o] = p, fix[o] = rand(),
lc[o] = rc[o] = pre[o] = suf[o] = 0, sz[o] = 1;
return o;
}
inline void up(int o) {
sz[o] = sz[lc[o]] + sz[rc[o]] + 1;
}
int make(int x, int y) {
if (!x || !y) return x | y;
return fix[x] > fix[y]
? (rc[x] = make(rc[x], y), up(x), x)
: (lc[y] = make(x, lc[y]), up(y), y);
}
pii split(int x, point k) {
if (!x) return make_pair(0, 0);
pii y; key[x] <= k
? (y = split(rc[x], k), rc[x] = y.fi, y.fi = x)
: (y = split(lc[x], k), lc[x] = y.se, y.se = x);
return up(x), y;
}
inline int kth(int x, int k) {
if (!x) return 0;
for (;;) {
int lsz = sz[lc[x]] + 1;
if (lsz == k) return x;
if (lsz > k) x = lc[x];
else k -= lsz, x = rc[x];
}
}
point getL(int u, point p) {
if (!u) return point(-inf, -inf);
if (!pre[u] || cross(key[pre[u]], key[u], p) < 0)
return max(key[u], getL(rc[u], p));
return getL(lc[u], p);
}
point getR(int u, point p) {
if (!u) return point(inf, inf);
if (!suf[u] || cross(key[suf[u]], key[u], p) > 0)
return min(key[u], getR(lc[u], p));
return getR(rc[u], p);
}
inline void init() {
tot = rt = 0;
}
inline void insert(point p) {
pii x = split(rt, p);
int a = kth(x.fi, sz[x.fi]), b = suf[a];
if (a && b && cross(key[a], p, key[b]) >= 0||a&&key[a]==p) {
rt = make(x.fi, x.se);
return;
}
point L = getL(x.fi, p), R = getR(x.se, p);
pii y = split(x.fi, L), z = split(x.se, point(R.x, R.y - 1));
a = kth(y.fi, sz[y.fi]), b = kth(z.se, 1);
int o = nw(p);
pre[o] = a, suf[o] = b;
if (a) suf[a] = o;
if (b) pre[b] = o;
rt = make(y.fi, make(o, z.se));
}
ll dfs(int u, point p) {
ll res = dot(p, key[u]);
if (rc[u] && dot(p, key[suf[u]]) >= res) return dfs(rc[u], p);
if (lc[u] && dot(p, key[pre[u]]) >= res) return dfs(lc[u], p);
return res;
}
inline ll query(point p) {
return rt ? dfs(rt, p) : 0;
}
}
可持久化
只需要类似主席树那样拷贝即可。
namespace treap{
int lc[N],rc[N],sz[N],key[N],val[N];
int size=0;
inline int nw(int x){
int o=++size;
key[o]=rand();
val[o]=x;
sz[o]=1;
return o;
}
inline int copy(int x){
int o=nw(val[x]);
key[o]=key[x];
sz[o]=sz[x];
lc[o]=lc[x];
rc[o]=rc[x];
return o;
}
inline void up(int o){
sz[o]=sz[lc[o]]+1+sz[rc[o]];
}
inline int merge(int x,int y){
if(!x||!y)return x|y;
if(key[x]<key[y]){
int o=copy(x);
rc[o]=merge(rc[o],y);
return up(o),o;
}
else{
int o=copy(y);
lc[o]=merge(x,lc[o]);
return up(o),o;
}
}
inline pii split(int o,int k){
if(!o)return mp(0,0);
if(k==0)return mp(0,o);
if(k==sz[o])return mp(o,0);
if(k<=sz[lc[o]]){
int u=copy(o);
pii y=split(lc[u],k);
lc[u]=y.se;
return up(u),mp(y.fi,u);
}
else{
int u=copy(o);
pii y=split(rc[u],k-1-sz[lc[u]]);
rc[u]=y.fi;
return up(u),mp(u,y.se);
}
}
inline int ins(int o,int k,int x){
pii y=split(o,k-1);
return merge(y.fi,merge(nw(x),y.se));
}
inline int del(int o,int k){
pii y=split(o,k-1);
pii z=split(y.se,1);
return merge(y.fi,z.se);
}
inline int qry(int o,int k){
for(;;){
if(k==sz[lc[o]]+1)return val[o];
if(k<=sz[lc[o]])o=lc[o];
else k-=1+sz[lc[o]],o=rc[o];
}
}
}
线段树嵌套treap
注意treap的懒标记是全局的,所以也需要在线段树上放
const int N=250000*50;
namespace treap{
struct node{
int lc,rc,key,sz,tag,val,best,lzy;
}T[N];
int stk[N],siz,top;
inline int nw(int p,int owo){
int o;
if(top)o=stk[top--];
else o=++siz;
T[o].lc=T[o].rc=T[o].lzy=0;
T[o].key=rand();
T[o].sz=1;
T[o].tag=p;
T[o].val=owo;
T[o].best=owo;
return o;
}
inline void push(int o){
stk[++top]=o;
}
inline void plus(int o,int x){
if(o)T[o].tag+=x,T[o].lzy+=x;
}
inline void down(int o){
if(!T[o].lzy)return;
if(T[o].lc)plus(T[o].lc,T[o].lzy);
if(T[o].rc)plus(T[o].rc,T[o].lzy);
T[o].lzy=0;
}
inline void up(const int &o){
T[o].sz=T[T[o].lc].sz+1+T[T[o].rc].sz;
T[o].best=max(T[o].val,max(T[T[o].lc].best,T[T[o].rc].best));
}
inline int make(int x,int y){
if(!x||!y)return x|y;
down(x),down(y);
if(T[x].key<T[y].key){
T[x].rc=make(T[x].rc,y);
return up(x),x;
}
T[y].lc=make(x,T[y].lc);
return up(y),y;
}
pii split(int o,int k){
if(!o)return mp(0,0);
down(o);
if(k<T[o].tag){
pii y=split(T[o].lc,k);
T[o].lc=y.se,y.se=o;
return up(o),y;
}
pii y=split(T[o].rc,k);
T[o].rc=y.fi,y.fi=o;
return up(o),y;
}
int count(int &rt,int l,int r){
if(!rt)return 0;
//printf("@ %d %d %d\n",rt,l,r);
pii x=split(rt,l-1);
pii y=split(x.se,r);
int res=T[y.fi].sz;
rt=make(x.fi,make(y.fi,y.se));
return res;
}
int getmx(int &rt,int l,int r){
if(!rt)return 0;
pii x=split(rt,l-1);
pii y=split(x.se,r);
int res=T[y.fi].best;
rt=make(x.fi,make(y.fi,y.se));
return res;
}
void add(int &rt,int a,int b){
pii x=split(rt,a-1);
rt=make(x.fi,make(nw(a,b),x.se));
}
void chg(int &rt,int a,int b){
pii x=split(rt,a-1);
pii y=split(x.se,a);
down(y.fi),T[y.fi].val=b,up(y.fi);
rt=make(x.fi,make(y.fi,y.se));
}
int del(int &rt,int a){
pii x=split(rt,a-1);
pii y=split(x.se,a);
int res=T[y.fi].val;
push(y.fi);
rt=make(x.fi,y.se);
return res;
}
int find(int o,int k){
if(!o)return 0;
if(T[o].tag==k)return 1;
down(o);
if(k<T[o].tag)return find(T[o].lc,k);
return find(T[o].rc,k);
}
}
const int inf=1e6;
const int M=1000000*25;
namespace seg{
int lc[M],rc[M],cur[M],shit[M];
int stk[M],sz,top;
inline int nw(){
int o;
if(top)o=stk[top--];
else o=++sz;
lc[o]=rc[o]=cur[o]=shit[o]=0;
return o;
}
inline void push(int o){
stk[++top]=o;
}
void plus(int o,int x){
if(!o)return;
treap::plus(cur[o],x);
shit[o]+=x;
}
void down(int o){
if(!shit[o])return;
plus(lc[o],shit[o]);
plus(rc[o],shit[o]);
shit[o]=0;
}
#define mid ((l + r) >> 1)
int build(int l,int r,int p,int A,int B){
int o=nw();
treap::add(cur[o],p,B);
if(l==r)return o;
if(A<=mid)lc[o]=build(l,mid,p,A,B);
else rc[o]=build(mid+1,r,p,A,B);
return o;
}
int del(int o,int l,int r,int p){
if(!treap::find(cur[o],p))return 0;
down(o);
int owo=treap::del(cur[o],p);
if(l==r)return owo;
int tmp=del(lc[o],l,mid,p);
int tmp2=del(rc[o],mid+1,r,p);
return max(tmp,tmp2);
}
void ins(int &o,int l,int r,int p,int A,int B){
if(!o)o=nw();
down(o);
treap::add(cur[o],p,B);
if(l==r)return;
if(A<=mid)ins(lc[o],l,mid,p,A,B);
else ins(rc[o],mid+1,r,p,A,B);
}
void chgB(int o,int l,int r,int p,int nwB){
if(!treap::find(cur[o],p))return;
down(o);
treap::chg(cur[o],p,nwB);
if(l==r)return;
chgB(lc[o],l,mid,p,nwB);
chgB(rc[o],mid+1,r,p,nwB);
}
int merge(int x,int y,int l,int r){
down(x),down(y);
if(!x||!y)return x|y;
cur[x]=treap::make(cur[x],cur[y]);
if(l==r)return push(y),x;
lc[x]=merge(lc[x],lc[y],l,mid);
rc[x]=merge(rc[x],rc[y],mid+1,r);
return push(y),x;
}
int qryA(int o,int l,int r,int x,int y,int L,int R){
if(l==x&&y==r){
return treap::count(cur[o],L,R);
}
down(o);
if(y<=mid)return qryA(lc[o],l,mid,x,y,L,R);
if(mid<x)return qryA(rc[o],mid+1,r,x,y,L,R);
return qryA(lc[o],l,mid,x,mid,L,R)
+ qryA(rc[o],mid+1,r,mid+1,y,L,R);
}
int qryB(int o,int l,int r,int K,int L,int R){
if(l==r)return l;
down(o);
int tmp=treap::count(cur[rc[o]],L,R);
//printf("%d %d %d %d %d\n",l,r,L,R,tmp);
if(K<=tmp)return qryB(rc[o],mid+1,r,K,L,R);
return qryB(lc[o],l,mid,K-tmp,L,R);
}
int qryC(int o,int l,int r,int x,int y,int L,int R){
if(l==x&&y==r)
return treap::getmx(cur[o],L,R);
down(o);
if(y<=mid)return qryC(lc[o],l,mid,x,y,L,R);
if(mid<x)return qryC(rc[o],mid+1,r,x,y,L,R);
return max(qryC(lc[o],l,mid,x,mid,L,R),
qryC(rc[o],mid+1,r,mid+1,y,L,R));
}
#undef mid
}
维护线段
需要一些分类讨论
/**Treap**/
int lc[N],rc[N],sz[N],key[N],L[N],R[N];
int len[N],rev[N],lazy[N],rt,size;
inline int nw(int l,int r){
int o=++size;
if(l<=r)L[o]=l,R[o]=r;
else L[o]=r,R[o]=l,rev[o]=1;
key[o]=rand(),sz[o]=len[o]=abs(r-l)+1;
return o;
}
inline void reverse(int o){
if(!o)return;
swap(lc[o],rc[o]);
lazy[o]^=1,rev[o]^=1;
}
inline void down(int o){
if(lazy[o]){
reverse(lc[o]);
reverse(rc[o]);
lazy[o]=0;
}
}
inline void up(int o){
sz[o]=sz[lc[o]]+len[o]+sz[rc[o]];
}
int make(int x,int y){
if(!x||!y)return x|y;
down(x),down(y);
if(key[x]<key[y]){
rc[x]=make(rc[x],y);
return up(x),x;
}
else{
lc[y]=make(x,lc[y]);
return up(y),y;
}
}
pii splitseg(int x,int k){
pii y;
if(!rev[x]){
y.fi=nw(L[x],L[x]+k-1);
y.se=nw(L[x]+k,R[x]);
}
else{
y.fi=nw(R[x],R[x]-k+1);
y.se=nw(R[x]-k,L[x]);
}
return y;
}
pii split(int x,int k){
if(!x)return mp(0,0);
if(!k)return mp(0,x);
if(k==sz[x])return mp(x,0);
down(x);
if(!lc[x]&&!rc[x])return splitseg(x,k);
pii y;
if(k<=sz[lc[x]]){
y=split(lc[x],k);
lc[x]=y.se,y.se=x;
return up(x),y;
}
else if(k>=len[x]+sz[lc[x]]){
y=split(rc[x],k-len[x]-sz[lc[x]]);
rc[x]=y.fi,y.fi=x;
return up(x),y;
}
else{
int LC=lc[x],RC=rc[x];
y=splitseg(x,k-sz[lc[x]]);
lc[y.fi]=LC,rc[y.se]=RC;
up(y.fi),up(y.se);
return y;
}
}
void Mov(int l,int r){
pii x=split(rt,l-1);
pii y=split(x.se,r-l+1);
rt=make(y.fi,make(x.fi,y.se));
}
void Rev(int l,int r){
pii x=split(rt,l-1);
//printf("# %d\n",sz[x.fi]);
pii y=split(x.se,r-l+1);
reverse(y.fi);
//printf("! %d %d\n",sz[y.fi],sz[y.se]);
rt=make(x.fi,make(y.fi,y.se));
//printf("@ %d\n",sz[rt]);
}
int clk;
void print(int o){
if(!o)return;
down(o);
print(lc[o]);
if(!rev[o])v.pb(mp(L[o],R[o]));
else v.pb(mp(R[o],L[o]));
print(rc[o]);
}
注意实现
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(i,n) for(int i=(0);i<(n);i++)
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using namespace std;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef long long lll;
typedef long long ll;
inline int read(){
char ch=getchar();int x=0,op=0;
while(!isdigit(ch))op|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return op?-x:x;
}
const int N=200005;
struct P{
ll x,y;
P(ll _x=0,ll _y=0){x=_x,y=_y;}
friend P operator + (const P &a,const P &b){
return P(a.x+b.x,a.y+b.y);
}
friend P operator - (const P &a,const P &b){
return P(a.x-b.x,a.y-b.y);
}
friend lll operator * (const P &a,const P &b){
return (lll)a.x*b.y-(lll)a.y*b.x;
}
inline ll f(const int &k){return k*x+y;}
}emp;
vector<pair<int,P>> g[N],e[N];
vector<P> L,R,all;
int n,m;
void rebuild(int u,int fa){
vector<pair<int,P>> son;
for(auto v:g[u])
if(v.fi!=fa){
rebuild(v.fi,u);
son.pb(v);
}
int last=u,now;
for(auto v:son){
now=++n;
e[last].pb(mp(now,emp));
e[now].pb(mp(last,emp));
e[now].pb(mp(v.fi,v.se));
e[v.fi].pb(mp(now,v.se));
last=now;
}
}
void convex(vector<P> &p){
vector<P> res;
sort(p.begin(),p.end(),[&](const P &a,const P &b){
return a.x<b.x||a.x==b.x&&a.y>b.y;
});
int m=0;
REP(i,p.size()){
if(i&&p[i].x==p[i-1].x)continue;
while(m&&res[m-1].y<=p[i].y)
res.pop_back(),m--;
while(m>=2&&(p[i]-res[m-2])*(res[m-1]-res[m-2])<=0)
res.pop_back(),m--;
res.pb(p[i]),m++;
}
p=res;
}
void merge(){
all.pb(L[0]+R[0]);
for(int i=0,j=0;i+1<L.size()||j+1<R.size();)
if(j+1==R.size()||(i+1<L.size()&&(L[i+1]-L[i])
*(R[j+1]-R[j])<0))
all.pb(L[++i]+R[j]);
else
all.pb(L[i]+R[++j]);
}
P bas;
int sz[N],vis[N],rt,prt;
void find(int u,int fa,int s,P las){
sz[u]=1;
for(auto v:e[u])
if(v.fi!=fa&&!vis[v.fi]){
find(v.fi,u,s,v.se);
sz[u]+=sz[v.fi];
}
if(fa&&(!rt||max(sz[u],s-sz[u])<max(sz[rt],s-sz[rt])))
rt=u,prt=fa,bas=las;
}
void get(int u,int fa,vector<P> &p,P now){
p.pb(now);
for(auto v:e[u])
if(v.fi!=fa&&!vis[v.fi])
get(v.fi,u,p,now+v.se);
}
void divide(int x,int s){
if(s==1)return;
rt=0,find(x,0,s,emp);
int u=rt,v=prt;
int su=sz[u],sv=s-su;
L.clear(),get(u,v,L,emp);
R.clear(),get(v,u,R,bas);
convex(L),convex(R),merge();
vis[v]=1,divide(u,su),vis[v]=0;
vis[u]=1,divide(v,sv),vis[v]=0;
}
int main(){
n=read(),m=read();
if(n==1){
while(m--)puts("0");
return 0;
}
rep(i,1,n-1){
int u=read(),v=read();
int x=read(),y=read();
g[u].pb(mp(v,P(x,y)));
g[v].pb(mp(u,P(x,y)));
}
rebuild(1,0);
divide(1,n);
convex(all);
for(int i=0,j=0;i<m;i++){
while(j+1<all.size()&&all[j+1].f(i)>all[j].f(i))j++;
printf("%lld%c",all[j].f(i)," \n"[i==m-1]);
}
return 0;
}
May holiday
可以暴力建虚树
#include<bits/stdc++.h>
#define rep(i,a,b) for (int i=(a); i<=(b); i++)
#define per(i,a,b) for (int i=(a); i>=(b); i--)
#define REP(i,n) for (int i=(0); i<(n); i++)
#define clr(x) memset(x, 0, sizeof x)
using namespace std;
const int N = 100005, M = 500;
int on[N], c[N], cur[N], ex[N], s[N], f[N];
int p[N], t[N], q[N], h[N], pa[N];
vector<pair<int,int> > v[N];
vector<int> e[N];
int n, m, ans;
int clk;
void dfs(int u, int fa) {
h[++clk] = u;
for (auto v : e[u])
if (v != fa) dfs(v, u);
}
int main() {
scanf("%d%d", &n, &m);
rep (i, 2, n) scanf("%d", &p[i]), e[p[i]].push_back(i);
dfs(1, 0);
rep (i, 1, n) scanf("%d", &t[i]);
rep (i, 1, m) scanf("%d", &q[i]);
for (int l = 1, r = min(M, m); l <= m; l = r + 1, r = min(r + M, m)) {
clr(on), clr(c);
rep (i, l, r) on[abs(q[i])] = 1;
per (i, n, 1) {
int x = h[i];
if (c[x] >= 2) on[x] = 1;
if (on[x] || c[x]) c[p[x]] ++;
}
rep (i, 1, n) {
int x = h[i];
if (on[p[x]]) pa[x] = p[x];
else pa[x] = pa[p[x]];
}
rep (i, 1, n) if (on[i]) {
vector<int> tmp;
for (int x = p[i]; x && !on[x]; x = p[x])
if (!s[x]) tmp.push_back(t[x]);
sort(tmp.begin(), tmp.end());
for (int l = 0, r = 0; l < tmp.size(); l = r + 1, r = l) {
while (r + 1 < tmp.size() && tmp[l] == tmp[r + 1]) r ++;
v[i].push_back(make_pair(tmp[l], r - l + 1));
}
cur[i] = -1; ex[i] = 0;
while (cur[i] + 1 < v[i].size() && v[i][cur[i] + 1].first < 0)
cur[i] ++;
}
rep (i, l, r) {
int u = abs(q[i]), op = q[i] / u;
if (t[u] < 0 && !s[u]) ans --;
s[u] += op;
if (t[u] < 0 && !s[u]) ans ++;
for (int x = u; x; x = pa[x]) {
if (x != u) {
if (t[x] < 0 && !s[x]) ans --;
t[x] -= op;
if (t[x] < 0 && !s[x]) ans ++;
}
ex[x] += op;
while (cur[x] + 1 < v[x].size()
&& v[x][cur[x] + 1].first - ex[x] < 0)
ans += v[x][++cur[x]].second;
while (cur[x] >= 0
&& v[x][cur[x]].first - ex[x] >= 0)
ans -= v[x][cur[x]--].second;
}
printf("%d ", ans);
}
clr(f);
rep (i, l, r) f[abs(q[i])] += (q[i] > 0 ? 1 : -1);
per (i, n, 1) {
int x = h[i];
f[p[x]] += f[x];
}
rep (i, 1, n) if (!on[i]) t[i] -= f[i];
rep (i, 1, n) if (on[i]) v[i].clear();
}
return 0;
}
把链拆成两条会容易写很多
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define REP(i,n) for(int i=(0);i<(n);++i)
#define pb push_back
using namespace std;
typedef vector<int> vi;
inline int read(){
char ch=getchar();int x=0,op=0;
while(!isdigit(ch))op|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return op?-x:x;
}
const int N=100005,M=502;
int in[N],out[N],fa[N],d[N],id[N],rt[N];
int f[N][M],g[N][M],h[N][M]; //f 向上跳k步到达的点
int n,Q,H,x,y,z; //g 步长为k时,不离开块的步数
vi e[N],w[N]; //h 步长为k,到达的位置
int clk;
inline int isanc(int a,int b){
return in[a]<=in[b]&&out[b]<=out[a];
}
void dfs(int u,int dep=0){
in[u]=++clk,id[clk]=u;
if(!dep||dep==H-1||dep==H)dep=0,rt[u]=u;
REP(i,e[u].size())
if(e[u][i]!=fa[u]){
d[e[u][i]]=d[u]+w[u][i];
fa[e[u][i]]=u;
dfs(e[u][i],dep+w[u][i]);
}
out[u]=clk;
}
void init(){
fa[1]=1,dfs(1,0);
rep(i,1,n){
int u=id[i];
if(!rt[u])rt[u]=rt[fa[u]];
}
rep(i,1,n){
int u=id[i],v=u;
rep(j,1,H){
if(v>=2&&d[u]-d[fa[v]]<=j)v=fa[v];
f[u][j]=v;
}
}
rep(i,1,n){
int u=id[i],v;
rep(j,1,H){
v=f[u][j];
if(u==v||rt[v]!=rt[u]){
g[u][j]=0,h[u][j]=u;
}
else{
g[u][j]=g[v][j]+1;
h[u][j]=h[v][j];
}
}
}
}
int bf1(int x,int y,int k){
int res=0,nxt;
for(;k<=H;){
if(d[y]>d[x])swap(x,y);
nxt=f[x][k];
if(isanc(nxt,y))break;
res++,x=nxt;
}
int dist=0;
while(x!=y){
if(d[y]>d[x])swap(x,y);
dist+=d[x]-d[fa[x]],x=fa[x];
}
return res+1+(dist>k);
}
int solve1(int x,int y,int k){
int res=0,nxt;
while(x!=y){
if(d[y]>d[x])swap(x,y);
nxt=h[x][k];
if(isanc(nxt,y))return res+bf1(x,y,k);
res+=g[x][k],x=nxt;
if(x==y)break;
nxt=f[x][k];
if(isanc(nxt,y))return res+bf1(x,y,k);
res++,x=nxt;
}
return res;
}
int jump(int x,int k){
while(k&&x>=2){
if(x==rt[x]){
if(d[x]-d[fa[x]]<=k)
k-=d[x]-d[fa[x]],x=fa[x];
else return x;
}
else if(d[x]-d[rt[x]]<=k)
k-=d[x]-d[rt[x]],x=rt[x];
else return f[x][k];
}
return x;
}
int solve2(int x,int y,int k){
int res=0,nxt;
while(x!=y){
if(d[y]>d[x])swap(x,y);
nxt=jump(x,k);
if(isanc(nxt,y))return res+bf1(x,y,k);
res++,x=nxt;
}
return res;
}
int main(){
n=read();
H=max(2,(int)sqrt(n));
rep(i,1,n-1){
x=read(),y=read(),z=read();
e[x].pb(y),w[x].pb(z);
e[y].pb(x),w[y].pb(z);
}
init();
Q=read();
while(Q--){
x=read(),y=read(),z=read();
if(z<=H)printf("%d\n",solve1(x,y,z));
else printf("%d\n",solve2(x,y,z));
}
return 0;
}
zkw 线段树
能够有效减小常数。适用于单点修改,区间查询的简单信息维护。
namespace seg {
const int b = 1<<18; int t[(1<<19)+5];
inline void init() { memset(t, 0x3f, sizeof t); }
inline void u(int x, int v) {
for (t[x+=b]=v, x>>=1; x; x>>=1)
t[x] = min(t[x<<1], t[x<<1|1]);
}
inline int q(int l, int r) {
int ans = inf;
for (l+=b-1, r+=b+1; l^r^1; l>>=1, r>>=1) {
if (~l&1) cmin(ans, t[l^1]);
if ( r&1) cmin(ans, t[r^1]);
}
return ans;
}
}
减少堆的常数
使用C语言的函数,略快于priority_queue
struct PQ {
node a[N * 5]; int w;
inline void push(const node &x) {
a[++w] = x; push_heap(a + 1, a + w + 1);
}
inline void pop() {
pop_heap(a + 1, a + w + 1); --w;
}
inline const node& top() {
return a[1];
}
} Q;
李超树
只需要支持插入线段,单点求最值。特别好写
struct L{
ll k,b;
L(ll _k=0,ll _b=-1e18){k=_k,b=_b;}
ll operator () (ll x){return k*x+b;}
};
struct seg{
L x;seg *lc,*rc;
seg():x(){lc=rc=0;};
void add(L y,ll l=0,ll r=1e9){
ll m=(l+r)>>1;
if(y(m)>x(m))swap(x,y);
if(x(l)<y(l)){
if(!lc)lc=new seg;
lc->add(y,l,m);
}
else if(x(r)<y(r)){
if(!rc)rc=new seg;
rc->add(y,m+1,r);
}
}
ll qry(ll k,ll l=0,ll r=1e9){
ll res=x(k),m=(l+r)>>1;
if(k<=m&&lc)res=max(res,lc->qry(k,l,m));
if(k>m&&rc)res=max(res,rc->qry(k,m+1,r));
return res;
}
}s,t;
数据结构拆分在namespace与struct中
例如树链上维护分块,或者SAM嵌套数据结构。拆分出来是一个很好的选择,减少调试难度。
同时可以结合指针动态开辟。
struct block{
int *pre,*suf,sz,L,R,ans,tag;
pii *a,*b,*c;
inline void doit(int flag){
if(flag){
pre[1]=0,suf[0]=1;
pre[sz+1]=sz,suf[sz]=sz+1;
ans=1;
rep(i,2,sz)
if(a[i].fi!=a[i-1].fi)pre[i]=i-1;
else pre[i]=pre[i-1];
per(i,sz-1,1)
if(a[i].fi!=a[i+1].fi)suf[i]=i+1;
else suf[i]=suf[i+1];
}
while(ans<=sz&&a[ans].fi+tag<=0)
ans=suf[ans];
while(pre[ans]&&a[pre[ans]].fi+tag>0)
ans=pre[pre[ans]]+1;
}
void build(int l,int r){
L=l,R=r,sz=r-l+1;
a=new pii[sz+3];
b=new pii[sz+3];
c=new pii[sz+3];
pre=new int[sz+3];
suf=new int[sz+3];
rep(i,1,sz)
a[i]=mp(w[id[l-1+i]],l-1+i);
sort(a+1,a+sz+1);
tag=ans=0,doit(1);
}
void upd(int l,int r,int ex){
if(l==L&&r==R)
return tag+=ex,doit(0);
int n=0,m=0,p=1,q=1,owo=1;
rep(i,1,sz)
if(l<=a[i].se&&a[i].se<=r)
b[++n]=mp(a[i].fi+ex+tag,a[i].se);
else
c[++m]=mp(a[i].fi+tag,a[i].se);
while(p<=n||q<=m)
if(p<=n&&(q>m||b[p]<c[q]))a[owo++]=b[p++];
else a[owo++]=c[q++];
tag=ans=0,doit(1);
}
int qry(int l,int r){
if(l==L&&r==R)return sz-ans+1;
int res=0;
rep(i,1,sz)if(l<=a[i].se&&a[i].se<=r)
res+=((a[i].fi+tag)>0);
return res;
}
}b[N];
ST表支持O(1)回答LCA
namespace Dis {
vector<pii> e[maxn];
int d[maxn], id[maxn], f[maxn<<1][lg], Lg[maxn<<1], n, clk;
inline void init(int _n) { n = _n; }
inline void link(int a, int b, int c) {
e[a].pb(mp(b, c));
e[b].pb(mp(a, c));
}
void dfs(int u, int fa) {
f[id[u] = ++clk][0] = d[u];
REP (i, e[u].size())
if (e[u][i].fi != fa) {
d[e[u][i].fi] = d[u] + e[u][i].se;
dfs(e[u][i].fi, u);
f[++clk][0] = d[u];
}
}
void prepare() {
memset(f, 0x3f, sizeof f);
dfs(1, 0); Lg[0] = -1;
rep (i, 1, clk) Lg[i] = Lg[i>>1] + 1;
rep (i, 1, 18) rep (j, 1, clk - (1 << i))
f[j][i] = min(f[j][i-1], f[j+(1<<(i-1))][i-1]);
}
inline int ask(int a, int b) {
static int t, res; res = d[a] + d[b];
a = id[a]; b = id[b];
if (a > b) swap(a, b); t = Lg[b-a+1];
return res - 2 * min(f[a][t], f[b-(1<<t)+1][t]);
}
}
void init(int lim){
rep(i,2,lim){
if(!flag[i])p[++cnt]=i,sp[cnt]=(sp[cnt-1]+i)%mod;
for (int j=1;j<=cnt&&i*p[j]<=lim;++j){
flag[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
}
inline int id(ll x){
return x<=T?b[x]:c[n/x];
}
void G(){
for (ll last=1,i;last<=n;last=i+1){
i=n/(n/last);a[++m]=n/i;
if(a[m]<=T)b[a[m]]=m;
else c[n/a[m]]=m;
h[m]=(a[m]-1)%mod;
g[m]=1ll*h[m]*(h[m]+3)%mod;
if(g[m]&1)g[m]+=mod;g[m]>>=1;
}
rep(j,1,cnt)
for(int i=1;i<=m&&a[i]>=1ll*p[j]*p[j];++i){
h[i]=(h[i]-(h[id(a[i]/p[j])]-(j-1)+mod)%mod+mod)%mod;
g[i]=(g[i]-1ll*p[j]*(g[id(a[i]/p[j])]-sp[j-1]+mod)%mod+mod)%mod;
}
}
int S(ll n,int k){
if(n<=1||p[k]>n)return 0;
int t=id(n);
ll res=(ll)g[t]-h[t]-(sp[k-1]-(k-1));
if(k==1)res+=2;
for(int i=k;i<=cnt&&1ll*p[i]*p[i]<=n;++i){
ll p1=p[i],p2=p1*p1;
for(int e=1;p2<=n;++e,p1=p2,p2*=p[i])
res+=(1ll*(p[i]^e)*S(n/p1,i+1)+(p[i]^(e+1)))%mod;
}
res%=mod;
//printf("%lld %d %d\n", n, k, res);
return res<0?res+mod:res;
}
const int N=1005,M=100005,inf=1e9;
struct edge{int u,v,f,c;};
struct ISAP{
int n,m,s,t;ll res;
int num[N],cur[N],d[N];
int link[M],h[N],p[N];
edge e[M];
inline void init(int _n){
n=_n,m=0,res=0;
memset(h,-1,sizeof h);
memset(cur,-1,sizeof cur);
}
inline void add(int u,int v,int w){
e[m]=(edge){u,v,0,w};
link[m]=h[u],cur[u]=h[u]=m++;
e[m]=(edge){v,u,0,0};
link[m]=h[v],cur[v]=h[v]=m++;
}
inline int aug(){
int mn=inf;
for(int x=t;x!=s;x=e[p[x]].u)
mn=min(mn,e[p[x]].c-e[p[x]].f);
for(int x=t;x!=s;x=e[p[x]].u)
e[p[x]].f+=mn,e[p[x]^1].f-=mn;
return mn;
}
int Maxflow(int _s,int _t){
int u=_s;s=_s,t=_t;
memset(num,0,sizeof num);
memset(d,0,sizeof d),num[0]=n;
while(d[s]<n){
if(u==t)res+=aug(),u=s;
int flag=0;
loop(k,cur[u])
if(e[k].f<e[k].c&&d[u]==d[e[k].v]+1){
cur[u]=k,p[u=e[k].v]=k;
flag=1;break;
}
if(flag)continue;
int mn=n;
loop(k,cur[u]=h[u])if(e[k].f<e[k].c)
mn=min(mn,d[e[k].v]+1);
if(!(--num[d[u]]))return res;
num[d[u]=mn]++,u=(u==s?s:e[p[u]].u);
}
return res;
}
}G;
背模板!!
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(i,n) for(int i=(0);i<(n);i++)
using namespace std;
const int N=405,inf=1e9+99;
int w[N][N],ex[N],ey[N],mn[N];
int vx[N],vy[N],cur[N],p[N];
int n,m,K,a,b,c;
int dfs(int x){
vx[x]=1;
rep(y,1,n)if(!vy[y]){
int d=ex[x]+ey[y]-w[x][y];
if(!d){
vy[y]=1;
if(!cur[y]||dfs(cur[y]))
return cur[y]=x,1;
}
else mn[y]=min(mn[y],d);
}
return 0;
}
long long KM(){
rep(x,1,n)rep(y,1,n)
ex[x]=max(ex[x],w[x][y]);
rep(x,1,n){
rep(y,1,n)mn[y]=inf;
memset(vx,0,sizeof vx);
memset(vy,0,sizeof vy);
if(dfs(x))continue;
for(;;){
int d=inf,t=0;
rep(y,1,n)if(!vy[y])d=min(d,mn[y]);
rep(x,1,n)if(vx[x])ex[x]-=d;
rep(y,1,n)if(vy[y])ey[y]+=d;
else if(!(mn[y]-=d))t=y;
if(!cur[t])break;
int e=cur[t];vx[e]=vy[t]=1;
rep(y,1,n)mn[y]=min(mn[y],ex[e]+ey[y]-w[e][y]);
}
memset(vx,0,sizeof vx);
memset(vy,0,sizeof vy);
dfs(x);
}
long long ans=0;
rep(y,1,n)ans+=w[cur[y]][y],p[cur[y]]=y;
return ans;
}
int main(){
scanf("%d%d%d",&n,&m,&K);
swap(n,m),n=max(n,m);
rep(i,1,K){
scanf("%d%d%d",&a,&b,&c);
w[a][b]=c;
}
cout<<KM()<<endl;
rep(i,1,m)
if(w[i][p[i]]>0)printf("%d ",p[i]);
else putchar('0'),putchar(' ');
return 0;
}
由于稠密图访问的连续性,用vector可能会快很多
const int N=10005,M=300005,inf=1e9+99;
namespace G{ //注意只支持非负边权,否则需要spfa预处理
#define real d[u]+f[u]-f[t.v]
struct edge{int u,v,w,f,c,p;};vector<edge>e[N];
int d[N],f[N],s,t,n,m;
inline void init(int _n,int _s=0,int _t=0){
n=_n,s=(_s?_s:1),t=(_t?_t:n),m=0;
}
inline void add(int u,int v,int c,int w){
e[u].pb((edge){u,v,w,0,c,(int)e[v].size()});
e[v].pb((edge){v,u,-w,0,0,(int)e[u].size()-1});
}
struct node{
int d,v;
friend bool operator < (const node &a,const node &b){
return a.d>b.d;
}
};priority_queue<node>Q;
bool dij(){
rep(i,1,n){
f[i]=min(f[i]+d[i],inf);
d[i]=i==s?0:inf;
}
Q.push((node){0,s});
while(!Q.empty()){
int t=Q.top().d,u=Q.top().v;
Q.pop();if(t>d[u])continue;
REP(k,e[u].size()){
edge &t=e[u][k];
if(t.f<t.c&&real+t.w<d[t.v])
Q.push((node){d[t.v]=real+t.w,t.v});
}
}
return d[t]<inf;
}
int r[N],in[N];
int dfs(int u,int a){
if(u==t)return a;
int res=0;in[u]=1;
for(int &k=r[u];k<e[u].size();k++){
edge &t=e[u][k];
if(t.f<t.c&&real+t.w==d[t.v]&&!in[t.v]){
int now=dfs(t.v,min(a,t.c-t.f));
t.f+=now,e[t.v][t.p].f-=now,res+=now;
if(!(a-=now))break;
}
}
return in[u]=0,res;
}
void mcmf(int &flow,int &cost){
int now;
while(dij()){
rep(i,1,n)r[i]=0;
flow+=(now=dfs(s,inf));
cost+=now*(d[t]+f[t]);
}
}
}
用途:构造后缀树,后缀树上可以DP,LCT维护..
NOI 2015 品酒大会
namespace sam{
int t[N][26],fa[N],buf[N],mx[N],pos[N],a[N],tail=1,size=1;
ll sz[N],f[N],g[N],cnt[N],ans[N];
vi e[N],w[N];
int nw(int val){
return mx[++size]=val,f[size]=-inf,g[size]=inf,size;
}
void ins(int c,int id,int val){
int p=tail,np=nw(mx[p]+1);
pos[id]=np,f[np]=g[np]=val,sz[np]=1;
for(;!t[p][c];p=fa[p])t[p][c]=np;
if(!p)return(void)(fa[np]=1,tail=np);
int q=t[p][c];
if(mx[q]==mx[p]+1)fa[np]=q;
else{
int nq=nw(mx[p]+1);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
REP(k,26)t[nq][k]=t[q][k];
for(;p&&t[p][c]==q;p=fa[p])t[p][c]=nq;
}
tail=np;
}
void init(){
f[1]=-inf,g[1]=inf;
rep(i,1,size)buf[mx[i]]++;
rep(i,1,size)buf[i]+=buf[i-1];
rep(i,1,size)a[buf[mx[i]]--]=i;
rep(i,2,size){
int u=a[i];
e[fa[u]].pb(u);
w[fa[u]].pb(mx[u]-mx[fa[u]]);
}
}
void dfs(int u,int d){
REP(i,e[u].size()){
dfs(e[u][i],d+w[u][i]);
cnt[d]+=1ll*sz[u]*sz[e[u][i]];
sz[u]+=sz[e[u][i]];
if(f[u]>-inf)
ans[d]=max(ans[d],1ll*f[u]*f[e[u][i]]);
f[u]=max(f[u],f[e[u][i]]);
if(g[u]<inf)
ans[d]=max(ans[d],1ll*g[u]*g[e[u][i]]);
g[u]=min(g[u],g[e[u][i]]);
}
}
void solve(int n){
rep(i,0,n)ans[i]=-1ll*inf*inf;
dfs(1,0);
per(i,n-1,0){
cnt[i]+=cnt[i+1];
ans[i]=max(ans[i],ans[i+1]);
}
rep(i,0,n-1)
printf("%lld %lld\n",cnt[i],!cnt[i]?0:ans[i]);
}
}
SAM与dus on tree
绝佳搭档~
const int N=1200005;
namespace tool{
int c[N],S[N],len,tot;
set<int>::iterator i,j;
set<int> s;
#define lowbit(x) (x&-x)
inline void update(int c[],int x,int y){
for(;x<=len;x+=lowbit(x))c[x]+=y;
}
inline int query(int c[],int x){
int res=0;
for(;x;x-=lowbit(x))res+=c[x];
return res;
}
int qry(int k){
return k*(tot-query(c,k))+query(S,k);
}
void upd(int l,int op){
l=(l+len)%len;if(l==0)l=len;
update(c,l,op),tot+=op;
update(S,l,op*l);
}
void add(int p,int op){
if(op==1)s.insert(p);
else s.erase(p);
if(s.empty()||op==1&&s.size()==1)
return upd(0,op);
j=s.upper_bound(p);
if(j==s.end())j=s.begin();
i=s.lower_bound(p);
if(i==s.begin())i=s.end();--i;
upd(*j-*i,-op);
upd(*j-p,op),upd(p-*i,op);
}
}
int ans[N];
namespace sam{
int t[N][26],fa[N],mx[N],owo[N];
int sz[N],sn[N],f[N][24];
int size=1,tail=1,clk;
vector<pii> q[N];
vi e[N];int id[N];
void init(){tail=1;}
inline int nw(int x,int y=0){
return mx[++size]=x,owo[size]=y,size;
}
int ins(int c,int val=0){
int p=tail,np=nw(mx[p]+1,val);
for(;p&&!t[p][c];p=fa[p])t[p][c]=np;
if(!p)return fa[np]=1,tail=np;
int q=t[p][c];
if(mx[q]==mx[p]+1)fa[np]=q;
else{
int nq=nw(mx[p]+1);
fa[nq]=fa[q],fa[q]=fa[np]=nq;
REP(k,26)t[nq][k]=t[q][k];
for(;p&&t[p][c]==q;p=fa[p])t[p][c]=nq;
}
return tail=np;
}
void predfs(int u){
sz[u]=1,id[++clk]=u;
rep(i,1,23)f[u][i]=f[f[u][i-1]][i-1];
for(auto v:e[u]){
f[v][0]=u,predfs(v),sz[u]+=sz[v];
if(sz[v]>sz[sn[u]])sn[u]=v;
}
}
void build(){
rep(i,2,size)e[fa[i]].pb(i);
predfs(1);
}
void add(int len,int p,int k,int id){
per(i,23,0)
if(mx[f[p][i]]>=len)p=f[p][i];
q[p].pb(mp(k,id));
}
void doit(int u,int ty){
if(owo[u]&&ty)tool::add(owo[u],1);
if(owo[u]&&!ty)tool::add(owo[u],-1);
for(auto v:e[u])doit(v,ty);
}
void solve(int u){
for(auto v:e[u])if(v!=sn[u])
solve(v),doit(v,0);
if(sn[u])solve(sn[u]);
for(auto v:e[u])if(v!=sn[u])
doit(v,1);
if(owo[u])tool::add(owo[u],1);
for(auto p:q[u])
ans[p.se]=tool::qry(p.fi);
}
}
用途:快速比较LCP,经常配合ST表使用。几乎都可以被SAM代替。
NOI2016 优秀的拆分
求所有形如 的子串拆分数。
注意:多组数据,数组及时清空。
#include<bits/stdc++.h>
#define rep(i,a,b) for (int i=(a); i<=(b); i++)
#define per(i,a,b) for (int i=(a); i>=(b); i--)
#define clr(x) memset(x, 0, sizeof x)
using namespace std;
const int maxn = 60005;
int SA[maxn], rank[maxn], height[maxn], tmp[maxn], tax[maxn];
int pre[maxn], suf[maxn], f[maxn][20], lg[maxn], n, m, l, r;
char s[maxn]; long long ans;
inline bool cmp(int a[maxn], int x, int y, int w) {
return a[x] == a[y] && a[x+w] == a[y+w];
}
void Sort(int n, int m) {
rep (i, 0, m) tax[i] = 0;
rep (i, 1, n) tax[rank[i]]++;
rep (i, 1, m) tax[i] += tax[i-1];
per (i, n, 1) SA[tax[rank[tmp[i]]]--] = tmp[i];
}
void SuffixArray(char s[maxn], int n) {
clr(height); clr(rank); clr(tmp); clr(SA);
rep (i, 1, n) { rank[i] = s[i]; tmp[i] = i; }
m = 127; Sort(n, m);
for (int w=1,p=0,i; w<n; w+=w,m=p,p=0) {
rep (i, n-w+1, n) tmp[++p] = i;
rep (i, 1, n) if (SA[i] > w) tmp[++p] = SA[i] - w;
Sort(n, m); swap(tmp, rank); rank[SA[1]] = p = 1;
rep (i, 2, n) rank[SA[i]] = (cmp(tmp, SA[i-1], SA[i], w) ? p : ++p);
}
for (int i=1,j,k=0; i<=n; height[rank[i++]]=k)
for (k=k?k-1:k,j=SA[rank[i]-1]; s[i+k]==s[j+k]; k++);
}
void pre_ST(int n, int a[maxn]) {
clr(f); lg[1] = 0;
rep (i, 2, n) lg[i] = lg[i>>1] + 1;
rep (i, 1, n) f[i][0] = a[i];
rep (j, 1, 18) rep (i, 1, n)
if (i+(1<<(j-1)) > n) f[i][j] = f[i][j-1];
else f[i][j] = min(f[i][j-1], f[i+(1<<(j-1))][j-1]);
}
inline int query(int l, int r) {
int t = lg[r - l + 1];
return min(f[l][t], f[r-(1<<t)+1][t]);
}
inline int getLCP(int x, int y) {
if (rank[x] > rank[y]) swap(x, y);
return query(rank[x]+1, rank[y]);
}
inline int revLCP(int x, int y) {
x = 2*n+2-x; y = 2*n+2-y;
if (rank[x] > rank[y]) swap(x, y);
return query(rank[x]+1, rank[y]);
}
int main() {
int T; scanf("%d", &T);
while (T--) {
clr(s); scanf("%s", s + 1); n = strlen(s + 1);
rep (i, 1, n) s[2*n+2-i] = s[i]; s[n+1] = '#';
SuffixArray(s, 2*n+1); pre_ST(2*n+1, height);
clr(pre); clr(suf);
rep (L, 1, n) rep (p, 1, n/L-1) {
l = min(revLCP(p*L, p*L+L), L);
r = min(getLCP(p*L, p*L+L), L);
if (r+l-1 < L) continue;
pre[p*L+L-l+1+L-1]++; pre[p*L+L+r]--;
suf[p*L-l+1]++; suf[p*L+r-1-L+1+1]--;
}
ans = 0;
rep (i, 1, n) {
pre[i] += pre[i-1]; suf[i+1] += suf[i];
ans += 1LL * pre[i] * suf[i+1];
}
printf("%lld\n", ans);
}
return 0;
}
注意链上可能需要特判LCA
void tj(int u, int f) {
dfn[u] = low[u] = ++c; st[++tp] = u;
for (int k=G.h[u]; k; k=G.l[k]) if (G.v[k] != f)
if (!dfn[G.v[k]]) {
tj(G.v[k], u);
cmin(low[u], low[G.v[k]]);
if (low[G.v[k]] >= dfn[u]) {
w[++t] = inf; T.A(u, t);
do T.A(st[tp], t); while (st[tp--] != G.v[k]);
}
}
else cmin(low[u], dfn[G.v[k]]);
}
又短又好写
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define REP(i,n) for(int i=(0);i<(n);i++)
#define pb push_back
using namespace std;
typedef vector<int> vi;
const int N=505;
int cur[N],vis[N],r[N],tim,n,m,ans,a,b;
vi e[N];
int dfs(int x){
if(!x)return 1;
vis[x]=tim;
vi::iterator it=e[x].begin();
vi::iterator ti=e[x].end();
random_shuffle(it,ti);
for(int u,v;it!=ti;it++){
u=*it,v=cur[u];
if(vis[v]<tim){
cur[x]=u,cur[u]=x,cur[v]=0;
if(dfs(v))return 1;
cur[u]=v,cur[v]=u,cur[x]=0;
}
}
return 0;
}
int main(){
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d",&a,&b);
e[a].pb(b),e[b].pb(a);
}
srand(time(NULL) ^ (long int)(new char));
rep(i,1,n)r[i]=i;
rep(T,1,3){
random_shuffle(r+1,r+n+1);
rep(i,1,n)if(!cur[r[i]])tim++,ans+=dfs(r[i]);
}
printf("%d\n",ans);
rep(i,1,n)printf("%d ",cur[i]);
return 0;
}