zoukankan      html  css  js  c++  java
  • 12.17 模拟赛

    T1 exploit

    题目大意:

    一棵树 每个点中有能量井,每个时刻,第$i$口井中回复$v_i$的能量;每口井有能量上限$l_i$

    $Q$次询问 每次询问$t,x,k$表示在$t$时刻提取$x$的子树中与$x$距离不超过$k$的井的能量 并输出提取的能量之和 保证$t$递增

    思路:

    首先题目被分为了两个关键部分:找到子树中距离不超过$k$的点与解决能量上限的问题

    对于第一个子问题 可以将树上的第$i$个点hash成平面中坐标为$(in_i,dep_i)$的点

    于是可以建立$kd-tree$ 查询相当于查询一个边界为$x=in_i,x=out_i,y=0,y=dep_i+k$矩形中的点 kd树基操

    修改的时候需要知道整个子树上一次修改的时间是否相同 如果不同就继续递归 否则整体修改

    (复杂度势能分析 会是不可能会的

    对于第二个子问题 我们在$kd-tree$的每个节点都设前缀和数组来方便统计子树的统计

    $limsum_i$表示该点子树中$frac {lim_j}{v_j} le i$的点的$lim$和 $vsum_i$表示该点子树中$frac {lim_j}{v_j} le i$的$v$之和

    对于一整个子树 设$x=t-$上次修改的时间,则答案为$limsum_x + (vsum_max- vsum_x) imes x$即可以表示已经到达上界和未到达上界的两部分

    而快速构造这个数组则可以在$build space kd-tree$时线段树合并

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<cstring>
     7 #include<vector>
     8 #include<stack>
     9 #include<queue>
    10 #include<map>
    11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i)
    12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i)
    13 #define ren for(int i=fst[x];i;i=nxt[i])
    14 #define Fill(x,t) memset(x,t,sizeof(x))
    15 #define ll long long
    16 #define ull unsigned long long
    17 #define inf 1000000000
    18 #define MAXN 170100
    19 #define MOD 998244353
    20 using namespace std;
    21 inline int read()
    22 {
    23     int x=0,f=1;char ch=getchar();
    24     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    25     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    26     return x*f;
    27 }
    28 int n,m,dep[MAXN],fa[MAXN],fst[MAXN],to[MAXN],nxt[MAXN],val[MAXN],ls[MAXN<<6],rs[MAXN<<6],rt[MAXN];
    29 int inc[MAXN],mx[MAXN],in[MAXN],ou[MAXN],cnt,Dim,tag[MAXN],tim[MAXN],las[MAXN],tot;
    30 ll smx[MAXN<<6],sinc[MAXN<<6],ans,s1,s2;
    31 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
    32 void dfs(int x){in[x]=++cnt;ren dep[to[i]]=dep[x]+val[i],dfs(to[i]);ou[x]=cnt;}
    33 struct node {int mx[2],mn[2],d[2],id,l,r,sz;node(){l=r=sz=0;}};
    34 bool operator < (const node a,const node b) {return a.d[Dim]<b.d[Dim];}
    35 void mdf(int &k,int kk,int l,int r,int p,int x1,int x2)
    36 {
    37     k=++tot;smx[k]=smx[kk]+x1,sinc[k]=sinc[kk]+x2;
    38     if(l==r) return ;int mid=l+r>>1;ls[k]=ls[kk],rs[k]=rs[kk];
    39     if(p<=mid) mdf(ls[k],ls[kk],l,mid,p,x1,x2);else mdf(rs[k],rs[kk],mid+1,r,p,x1,x2);
    40 }
    41 int merge(int x,int y)
    42 {
    43     if(!(x*y)) return x|y;int z=++tot;smx[z]=smx[x]+smx[y];
    44     sinc[z]=sinc[x]+sinc[y],ls[z]=merge(ls[x],ls[y]),rs[z]=merge(rs[x],rs[y]);return z;
    45 }
    46 void Query(int k,int l,int r,int x)
    47 {
    48     if(!k) return ;if(l==r) return ;
    49     int mid=l+r>>1;if(x<=mid) Query(ls[k],l,mid,x);
    50     else {s1+=smx[ls[k]],s2+=sinc[ls[k]];Query(rs[k],mid+1,r,x);}
    51 }
    52 struct kd_tree
    53 {
    54     node tr[MAXN],l,r;int Rt;
    55     void upd(int k)
    56     {
    57         l=tr[tr[k].l],r=tr[tr[k].r],tr[k].sz=l.sz+r.sz+1;
    58         rep(i,0,1)
    59         {
    60             if(tr[k].l) tr[k].mx[i]=max(tr[k].mx[i],l.mx[i]),tr[k].mn[i]=min(tr[k].mn[i],l.mn[i]);
    61             if(tr[k].r) tr[k].mx[i]=max(tr[k].mx[i],r.mx[i]),tr[k].mn[i]=min(tr[k].mn[i],r.mn[i]);
    62         }
    63     }
    64     int build(int l,int r,int now)
    65     {
    66         int mid=l+r>>1;Dim=now;nth_element(tr+l,tr+mid,tr+r+1);int id=tr[mid].id;
    67         rep(i,0,1) tr[mid].mn[i]=tr[mid].mx[i]=tr[mid].d[i];
    68         if(l<mid) tr[mid].l=build(l,mid-1,now^1);
    69         if(mid<r) tr[mid].r=build(mid+1,r,now^1);upd(mid);
    70         rt[mid]=merge(rt[tr[mid].l],rt[tr[mid].r]);
    71         mdf(rt[mid],rt[mid],0,inf,tim[id],mx[id],inc[id]);return mid;
    72     }
    73     void mem(){rep(i,1,n) tr[i].id=i,tr[i].d[0]=in[i],tr[i].d[1]=dep[i];Rt=build(1,n,0);}
    74     void pshd(int k){tag[tr[k].l]=tag[tr[k].r]=las[tr[k].l]=las[tr[k].r]=tag[k],tag[k]=-1;}
    75     void work(int k,int t)
    76     {
    77         if(!k) return ;
    78         if(tag[k]>=0) {s1=s2=0LL;Query(rt[k],0,inf,t-tag[k]);ans+=s1+(sinc[rt[k]]-s2)*((ll)t-tag[k]);return ;}
    79         else ans+=min((ll)mx[tr[k].id],(ll)inc[tr[k].id]*(t-las[k])),las[k]=t;
    80         work(tr[k].l,t);work(tr[k].r,t);
    81     }
    82     void query(int k,int x1,int x2,int y,int t)
    83     {
    84         if(!k) return ;if(tr[k].mx[0]<x1||tr[k].mn[0]>x2||tr[k].mn[1]>y) return ;
    85         if(tr[k].mn[0]>=x1&&tr[k].mx[0]<=x2&&tr[k].mx[1]<=y){work(k,t);tag[k]=las[k]=t;return ;}
    86         if(tag[k]>=0) pshd(k);if(tr[k].d[0]>=x1&&tr[k].d[0]<=x2&&tr[k].d[1]<=y)
    87             ans+=min((ll)mx[tr[k].id],(ll)inc[tr[k].id]*(t-las[k])),las[k]=t;
    88         query(tr[k].l,x1,x2,y,t);query(tr[k].r,x1,x2,y,t);
    89     }
    90 }kd;
    91 int main()
    92 {
    93     freopen("exploit.in","r",stdin);
    94     freopen("exploit.out","w",stdout);
    95     n=read();int Q,t,x,k;rep(i,1,n) inc[i]=read();rep(i,1,n) mx[i]=read(),tim[i]=(mx[i]-1)/inc[i];
    96     rep(i,2,n) fa[i]=read(),add(fa[i],i,read());cnt=0;dfs(1);Q=read();kd.mem();
    97     while(Q--) {t=read(),x=read(),k=read(),ans=0LL;kd.query(kd.Rt,in[x],ou[x],dep[x]+k,t);printf("%lld
    ",ans);}
    98 }
    View Code

    T2 cruise

    题目大意:

    $n$个城市 每个城市的坐标为$p_i$,到达每个城市必须花费$a_i$的时间来游玩

    从编号为$i$的城市可以到达编号为$[i+1,i+k]$的城市 路程花费时间为$|p_i-p_j| imes b_i$

    求从第一个城市到第$n$个城市的最短时间

    思路:

    可以得到dp方程: $dp_i = dp_j + |p_i-p_j| imes b_i ,i-k le j le i-1$

    一眼斜优+线段树分治 但是发现这个dp方程要分类讨论很难搞

    这些直线可以用李超树维护(学到了斜优的新姿势

    依然线段树分治 对于每个点 将该点对应的直线分为两部分 分别加入到李超线段树中

    对于$[1,p_i]$ 加入$k=-b_i,b=dp_i+p_j imes b_i$的直线;

    对于$[p_i,m]$ 加入$k=b_i,b=dp_i-p_j imes b_i$的直线

    因为李超线段树无法撤销 所以对于每个线段树分治中线段树的节点 都需要在当前节点统计对下面叶子节点的影响并消除这些线段

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<cstring>
     7 #include<vector>
     8 #include<stack>
     9 #include<queue>
    10 #include<map>
    11 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i)
    12 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i)
    13 #define ren(x) for(int i=fst[x];i;i=nxt[i])
    14 #define Fill(x,t) memset(x,t,sizeof(x))
    15 #define ll long long
    16 #define ull unsigned long long
    17 #define inf 1LL<<60
    18 #define MAXN 170100
    19 #define MOD 998244353
    20 using namespace std;
    21 inline int read()
    22 {
    23     int x=0,f=1;char ch=getchar();
    24     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    25     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    26     return x*f;
    27 }
    28 int n,m,k,p[MAXN],a[MAXN],b[MAXN],s[MAXN<<5],top;
    29 int fst[MAXN<<2],nxt[MAXN<<5],to[MAXN<<5],cnt;
    30 ll dp[MAXN];
    31 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
    32 struct seg{ll k,b;ll f(int x){return k*x+b;}}val[MAXN<<2];
    33 void build(int k,int l,int r)
    34 {
    35     val[k]=(seg){0,inf};if(l==r) return ;int mid=l+r>>1;
    36     build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    37 }
    38 void mdf(int k,int l,int r,seg x)
    39 {
    40     s[++top]=k;
    41     if(l==r) {if(x.f(l)<val[k].f(l)) val[k]=x;return ;}
    42     int mid=l+r>>1;
    43     if(x.f(mid)<val[k].f(mid)) swap(val[k],x);
    44     if(x.f(l)<val[k].f(l)) mdf(k<<1,l,mid,x);if(x.f(r)<val[k].f(r)) mdf(k<<1|1,mid+1,r,x);
    45 }
    46 void del(){while(top) val[s[top--]]=(seg){0,inf};}
    47 void ins(int k,int l,int r,int a,int b,seg x)
    48 {
    49     if(l==a&&r==b) {mdf(k,a,b,x);return ;}
    50     int mid=l+r>>1;
    51     if(b<=mid) ins(k<<1,l,mid,a,b,x);
    52     else if(a>mid) ins(k<<1|1,mid+1,r,a,b,x);
    53     else {ins(k<<1,l,mid,a,mid,x);ins(k<<1|1,mid+1,r,mid+1,b,x);}
    54 }
    55 ll query(int k,int l,int r,int x)
    56 {
    57     if(l==r) return val[k].f(x);
    58     int mid=l+r>>1;return min(val[k].f(x),x<=mid?query(k<<1,l,mid,x):query(k<<1|1,mid+1,r,x));
    59 }
    60 void Mdf(int k,int l,int r,int a,int b,int x)
    61 {
    62     if(l==a&&r==b) {add(k,x);return ;}
    63     int mid=l+r>>1;
    64     if(b<=mid) Mdf(k<<1,l,mid,a,b,x);
    65     else if(a>mid) Mdf(k<<1|1,mid+1,r,a,b,x);
    66     else {Mdf(k<<1,l,mid,a,mid,x);Mdf(k<<1|1,mid+1,r,mid+1,b,x);}
    67 }
    68 void solve(int k,int l,int r)
    69 {
    70     ren(k) ins(1,1,m,1,p[to[i]],(seg){-b[to[i]],dp[to[i]]+(ll)p[to[i]]*b[to[i]]}),
    71         ins(1,1,m,p[to[i]],m,(seg){b[to[i]],dp[to[i]]-(ll)p[to[i]]*b[to[i]]});
    72     if(fst[k]) {rep(i,l,r) dp[i]=min(dp[i],query(1,1,m,p[i])+a[i]);del();}
    73     if(l==r) return ;int mid=l+r>>1;solve(k<<1,l,mid);solve(k<<1|1,mid+1,r);
    74 }
    75 int main()
    76 {
    77     freopen("cruise.in","r",stdin);
    78     freopen("cruise.out","w",stdout);
    79     n=read(),m=read(),k=read();rep(i,1,n) p[i]=read();rep(i,1,n) a[i]=read(),dp[i]=inf;rep(i,1,n) b[i]=read();
    80     dp[1]=a[1];rep(i,1,n-1) Mdf(1,1,n,i+1,min(i+k,n),i);build(1,1,m);solve(1,1,n);printf("%lld
    ",dp[n]);
    81 }
    View Code

    T3 zoo

    题目大意:

    定义$f(S)$为对一个串$S$建立KMP树,其中0节点深度为0,树上所有节点的深度和

    给一个字符串$S$,$Q$次询问 每次询问一个$x$ 求$sum_{l=1}^x sum_{r=l}^x f(S[l:r])$

    思路:

    预处理出串中每个位置的答案 考虑$x+1$的答案与$x$的答案相差多少即所有$sum_{l=1}^{x+1} f(S[l:x+1])$ 

    发现这些KMP树实际上与之前的树并无什么区别 只是增加了这个节点 所以可以再次差分

    因此考虑如何计算这个点的在各个树中的深度之和 发现每棵树的深度即为跳过border的次数 +1

    计算跳过border的次数之和等价于计算以这个点结尾的字符串的出现次数之和

    所有串出现次数之和为不同串的个数$ imes$出现次数

    每个串的出现次数即$end-pos$集合大小为它子树的大小

    每新进一个点 我们可以将该点到根的路径上的每个点+该点包含不同串的个数,答案+不同串个数$ imes$ $end-pos$集合大小

    可以选择用LCT或离线+树链剖分来解决上述问题

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<cstring>
     7 #include<vector>
     8 #include<queue>
     9 #include<map>
    10 #define rep(i,s,t) for(register int i=(s),i__end=(t);i<=i__end;++i)
    11 #define dwn(i,s,t) for(register int i=(s),i__end=(t);i>=i__end;--i)
    12 #define ren for(int i=fst[x];i;i=nxt[i])
    13 #define Fill(x,t) memset(x,t,sizeof(x))
    14 #define ll long long
    15 #define inf 2139062143
    16 #define MAXN 350100
    17 #define MOD 998244353
    18 using namespace std;
    19 inline int read()
    20 {
    21     int x=0,f=1;char ch=getchar();
    22     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    23     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    24     return x*f;
    25 }
    26 int n,fa[MAXN],tr[MAXN][26],mxl[MAXN],tot,lst,rt,sz[MAXN],cnt,ans[MAXN];
    27 int fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],hsh[MAXN],HSH[MAXN],bl[MAXN],dep[MAXN];
    28 char ch[MAXN];
    29 inline void extend(int c)
    30 {
    31     int p=lst,np=lst=++tot;mxl[np]=mxl[p]+1,sz[np]=1;
    32     for(;p&&!tr[p][c];p=fa[p]) tr[p][c]=np;
    33     if(!p) {fa[np]=rt;return ;}
    34     int q=tr[p][c];if(mxl[q]==mxl[p]+1) {fa[np]=q;return ;}
    35     int nq=++tot;mxl[nq]=mxl[p]+1;
    36     memcpy(tr[nq],tr[q],sizeof(tr[nq]));fa[nq]=fa[q],fa[np]=fa[q]=nq;
    37     for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=nq;
    38 }
    39 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
    40 void dfs(int x)
    41 {
    42     ren {dep[to[i]]=dep[x]+1;dfs(to[i]);sz[x]+=sz[to[i]];}sz[x]++;
    43 }
    44 void dfs(int x,int anc)
    45 {
    46     hsh[x]=++cnt,HSH[cnt]=x,bl[x]=anc;int hvs=0;
    47     ren if(sz[to[i]]>sz[hvs]) hvs=to[i];
    48     if(!hvs) return ;dfs(hvs,anc);
    49     ren if(to[i]!=hvs) dfs(to[i],to[i]);
    50 }
    51 int sum[MAXN<<2],tag[MAXN<<2],v[MAXN<<2],num[MAXN];
    52 void pshd(int k)
    53 {
    54     (sum[k<<1]+=(ll)tag[k]*v[k<<1])%=MOD,(sum[k<<1|1]+=(ll)tag[k]*v[k<<1|1]);
    55     tag[k<<1]+=tag[k],tag[k<<1|1]+=tag[k],tag[k]=0;
    56 }
    57 void build(int k,int l,int r)
    58 {
    59     if(l==r) {v[k]=mxl[HSH[l]]-mxl[fa[HSH[l]]];return ;}
    60     int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    61     v[k]=(v[k<<1]+v[k<<1|1])%MOD;
    62 }
    63 void mdf(int k,int l,int r,int a,int b)
    64 {
    65     if(l==a&&r==b) {(sum[k]+=v[k])%=MOD,tag[k]++;return ;}
    66     int mid=l+r>>1;if(tag[k]) pshd(k);
    67     if(b<=mid) mdf(k<<1,l,mid,a,b);
    68     else if(a>mid) mdf(k<<1|1,mid+1,r,a,b);
    69     else {mdf(k<<1,l,mid,a,mid);mdf(k<<1|1,mid+1,r,mid+1,b);}
    70     sum[k]=(sum[k<<1]+sum[k<<1|1])%MOD;
    71 }
    72 int query(int k,int l,int r,int a,int b)
    73 {
    74     if(l==a&&r==b) return sum[k];
    75     int mid=l+r>>1;if(tag[k]) pshd(k);
    76     if(b<=mid) return query(k<<1,l,mid,a,b);
    77     else if(a>mid) return query(k<<1|1,mid+1,r,a,b);
    78     else return (query(k<<1,l,mid,a,mid)+query(k<<1|1,mid+1,r,mid+1,b))%MOD;
    79 }
    80 int Query(int x,int res=0)
    81 {
    82     while(bl[x]!=1) (res+=query(1,1,tot,hsh[bl[x]],hsh[x]))%=MOD,x=fa[bl[x]];
    83     return res+query(1,1,tot,1,hsh[x]);
    84 }
    85 void Mdf(int x)
    86 {
    87     while(bl[x]!=1) mdf(1,1,tot,hsh[bl[x]],hsh[x]),x=fa[bl[x]];
    88     mdf(1,1,tot,1,hsh[x]);
    89 }
    90 int main()
    91 {
    92     freopen("zoo.in","r",stdin);
    93     freopen("zoo.out","w",stdout);
    94     scanf("%s",ch+1);lst=tot=rt=1;n=strlen(ch+1);rep(i,1,n) extend(ch[i]-'a');
    95     rep(i,1,tot) add(fa[i],i);cnt=0;dfs(1);dfs(1,1);build(1,1,tot);int pos=1;
    96     rep(i,1,n) ans[i]=Query(pos=tr[pos][ch[i]-'a'])+i,Mdf(pos);
    97     rep(i,1,n) (ans[i]+=ans[i-1])%=MOD;rep(i,1,n) (ans[i]+=ans[i-1])%=MOD;int Q=read();
    98     while(Q--) printf("%d
    ",ans[read()]);
    99 }
    View Code
  • 相关阅读:
    第一周作业
    模拟赛3 题解
    模拟赛2 题解
    [HNOI2008]GT考试 题解
    NOI Online 提高组 题解
    模拟赛1 题解
    知识点拾遗
    [NOIp2012]疫情控制 题解
    [CEOI2002]Bugs Integrated, Inc. 题解
    [NOIp2017]宝藏 题解
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/10136423.html
Copyright © 2011-2022 走看看