T1:
之前考过的原题()
考虑由于修改每次都是从上到下
记
u
p
,
d
n
[
0
/
1
]
[
u
]
up,dn[0/1][u]
up,dn[0/1][u]表示原来/新的上到这里/这里到下的方案数
用桶维护祖先和子树的
d
p
dp
dp即可
祖先要用新的更新,子树用原来的
每次变化就是 + u p [ 1 ] ∗ d n [ 1 ] − u p [ 0 ] ∗ d n [ 0 ] +up[1]*dn[1]-up[0]*dn[0] +up[1]∗dn[1]−up[0]∗dn[0]
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline ll readll(){
char ch=gc();
ll res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline int readstring(char *s){
int top=0;char ch=gc();
while(isspace(ch))ch=gc();
while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
return top;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int mod=1e9+7;
inline int add(int a,int b){return (a+b)>=mod?(a+b-mod):(a+b);}
inline int dec(int a,int b){return (a<b)?(a-b+mod):(a-b);}
inline int mul(int a,int b){static ll r;r=(ll)a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){a=(a+b)>=mod?(a+b-mod):(a+b);}
inline void Dec(int &a,int b){a=(a<b)?(a-b+mod):(a-b);}
inline void Mul(int &a,int b){static ll r;r=(ll)a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(int x){return (x<0)?x+mod:x;}
cs int N=3000005;
int n,L,Q;
int fa[N],nw[N],val[N],p[N];
int pre[N],sub[N],up[2][N],dn[2][N];
vector<int> e[N];
void dfs1(int u){
up[0][u]=pre[val[u]-1],up[1][u]=pre[nw[u]-1];
Add(pre[nw[u]],up[1][u]);
ll pre1=sub[val[u]+1],pre2=sub[nw[u]+1];
for(int &v:e[u]){
dfs1(v);
}
Dec(pre[nw[u]],up[1][u]);
if(val[u]!=L)dn[0][u]=dec(sub[val[u]+1],pre1);
else dn[0][u]=1;
if(nw[u]!=L)dn[1][u]=dec(sub[nw[u]+1],pre2);
else dn[1][u]=1;
Add(sub[val[u]],dn[0][u]);
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
n=read(),L=read(),Q=read();
pre[0]=sub[L+1]=1;
for(int i=2;i<=n;i++)fa[i]=read()+1,e[fa[i]].pb(i);
for(int i=1;i<=n;i++)val[i]=read();
for(int i=1;i<=Q;i++)p[i]=read();
int res=0,ans=0;
for(int tt=0;tt<Q;tt+=n){
for(int i=1;i<=n&&i+tt<=Q;i++)nw[i]=p[i+tt];
dfs1(1);
if(tt==0)ans=sub[1];
for(int i=1;i<=n&&i+tt<=Q;i++)val[i]=nw[i];
for(int i=1;i<=n&&i+tt<=Q;i++){
Dec(ans,mul(up[0][i],dn[0][i]));
Add(ans,mul(up[1][i],dn[1][i]));
Add(res,mul(ans,i+tt));
// cout<<ans<<'\n';
}
}
cout<<res<<'\n';
return 0;
}
T2
考虑这个删除很奇妙的样子
考虑
T
T
T中每种字符第一个和最后一个提出来
这样会将序列划分成
51
51
51段
对于每个区间
如果被某个字符
c
c
c的
[
l
,
r
]
[l,r]
[l,r]包含
那么这个区间内和
S
S
S匹配时一定不能删去
c
c
c,否则必须删去
c
c
c
于是大力
k
m
p
kmp
kmp匹配即可
复杂度
O
(
n
c
)
O(nc)
O(nc)
由于博主是个大垃圾
写了个
O
(
n
2
c
)
O(n^2c)
O(n2c)暴力因为一些边界条件和傻逼错误调了半天
所以这里只有暴力代码
只需要写个
k
m
p
kmp
kmp和改一下暴力枚举即可优化掉一个
n
n
n
太懒了不想写了
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline ll readll(){
char ch=gc();
ll res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline int readstring(char *s){
int top=0;char ch=gc();
while(isspace(ch))ch=gc();
while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
return top;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=2000005;
int pos[N],cnt,n,m,pre[27],val[N];
int s[N],t[N];
ll f[N],g[N],sf[N];
char str[N];
typedef pair<pii,ll> piil;
vector<piil> tr;
inline void trans(int l,int r){
tr.clear();
if(l>r){
for(int i=1;i<=n+1;i++)tr.pb(piil(pii(i,i-1),0));return;
}
for(int i=1;i<=n;i++){
int p=i-1,fg=1;ll res=0;
for(int j=l;j<=r&&p<=n&&fg;j++){
while(s[p+1]!=t[j]){
if(pre[s[p+1]]){fg=0;break;}
else res+=val[p+1];
p++;
if(p>n){fg=0;break;}
}
p++;
}
if(fg)tr.pb(piil(pii(i,p),res));
}
}
int main(){
#ifdef Stargazer
freopen("lx.in","r",stdin);
#endif
n=readstring(str);
for(int i=1;i<=n;i++)s[i]=str[i]-'a';
m=readstring(str);
for(int i=1;i<=m;i++)t[i]=str[i]-'a';
for(int i=1;i<=n;i++)val[i]=read();
for(int i=n;i;i--)sf[i]=sf[i+1]+val[i];
sf[0]=sf[1];
pos[cnt=1]=0;
for(int i=1;i<=m;i++)
if(!pre[t[i]])pos[++cnt]=i,pre[t[i]]=1;
memset(pre,0,sizeof(pre));
for(int i=m;i;i--)
if(!pre[t[i]])pos[++cnt]=i,pre[t[i]]=1;
sort(pos+1,pos+cnt+1);
memset(f,127/3,sizeof(f));
f[0]=0;
memset(pre,0,sizeof(pre));
for(int i=2;i<=cnt;i++){
if(i>2){if(!pre[t[pos[i-1]]])pre[t[pos[i-1]]]=1;
else pre[t[pos[i-1]]]=0;}
if(pos[i-1]==pos[i])continue;
trans(pos[i-1]+1,pos[i]-1);
memset(g,127,sizeof(g));
for(piil &x:tr){
chemn(g[x.fi.se],f[x.fi.fi-1]+x.se);
}
memcpy(f,g,sizeof(g));
memset(g,127/3,sizeof(g));
int v=t[pos[i]];
for(int j=n;j;j--)if(s[j]==v){
chemn(g[j],f[j-1]);
for(int k=j-1;k;k--){
if(pre[s[k]]){break;};
chemn(g[j],f[k-1]+sf[k]-sf[j]);
}
}
memcpy(f,g,sizeof(g));
}
ll res=1e18;
for(int i=1;i<=n;i++)chemn(res,f[i]+sf[i+1]);
cout<<res<<'\n';
}
T3:
感觉可以四分树/树套树+ s e g m e n t b e a t s ? segment\ beats? segment beats?
先不考虑一个完全包含另一个人
每个点归给一个人
按
x
x
x从后往前做,用
s
e
t
set
set维护所有横着的线段
直接维护即可
考虑包含
如果一个包含另一个
其实只需要比较他们的时间
存在需要把一个的加给令一个
按时间用并查集维护维护即可
#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline ll readll(){
char ch=gc();
ll res=0;bool f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
inline int readstring(char *s){
int top=0;char ch=gc();
while(isspace(ch))ch=gc();
while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
return top;
}
template<typename tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<typename tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=300005;
int n,m,ans[N],fa[N],f[N],id[N];
pii a[N],b[N];
set<pii> st;
inline bool comp(int i,int j){
return b[i]>b[j];
}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main(){
#ifdef Stargazer
freopen("lx.in","r",stdin);
freopen("my.out","w",stdout);
#endif
n=read();
for(int i=1;i<=n;i++)a[i].fi=read(),a[i].se=read();
m=read();
for(int i=1;i<=m;i++)b[i].fi=read(),b[i].se=read();
b[m+1]=pii(1e9+1,1e9+1);
sort(a+1,a+n+1,greater<pii>());
for(int i=1;i<=m+1;i++)fa[i]=id[i]=i;
sort(id+1,id+m+2,comp);
st.insert(pii(0,-1));
for(int i=1,j=1;i<=m+1;i++){
int p=id[i];pii now=pii(b[p].se,p);
while(0721){
set<pii>::iterator it=--st.upper_bound(now);
if(it->se>p)st.erase(it);
else break;
}
if(p<m+1)f[p]=st.upper_bound(now)->se;
st.insert(now);
while(j<=n&&a[j].fi>b[id[i+1]].fi)ans[st.lower_bound(pii(a[j].se,-1))->se]++,j++;
}
for(int i=m;i;i--)f[i]=fa[i]=find(f[i]);
for(int i=m+1;i>1;i--)ans[f[id[i]]]+=ans[id[i]];
for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";return 0;
}