Loading

Noip模拟83 2021.10.26

T1 树上的数

有手就能在衡中$OJ$上过,但是$WaitingCoders$不行,就是这样

必须使用$O(n)$算法加上大力卡常,思路就是找子树内没更新的更新,更新过了直接$return$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,m,q1,vis[5000001],fa[5000001],a,b,X,Y,tmp,ans;
 4 struct SNOW{int to,next;}e[5000001];int head[5000001],rp;
 5 auto add=[](int x,int y){e[++rp]=(SNOW){y,head[x]};head[x]=rp;};
 6 inline int read(){
 7     int x=0,f=1;char ch=getchar();
 8     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 9     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
10     return x*f;
11 }
12 inline void dfs(int x){
13     if(!vis[x])return;tmp+=vis[x];vis[x]=0;
14     for(int i=head[x];i;i=e[i].next) dfs(e[i].to);
15 }
16 namespace WSN{
17     inline short main(){
18         freopen("tree.in","r",stdin);
19         freopen("tree.out","w",stdout);
20         n=read();m=read();a=read();b=read();q1=read();X=read();Y=read();
21         fa[1]=0;fa[2]=1;add(1,2);vis[1]=vis[2]=1;
22         for(int i=3;i<=n;++i){
23             fa[i]=((1ll*fa[i-1]*a+b)^19760817)%(i-1)+1;
24             add(fa[i],i);vis[i]=1;
25         }
26         dfs(q1);
27         ans=n-tmp;
28         for(int i=2;i<=m;++i){
29             q1=(((1ll*q1*X+Y)^19760817)^(i<<1))%(n-1)+2;
30             dfs(q1);
31             ans^=n-tmp;
32         }
33         printf("%d\n",ans);
34         return 0;
35     }
36 }
37 signed main(){return WSN::main();}
View Code

 

T2 时代的眼泪

名字一看挺猛,(不过原来的那次队长快跑+影魔+抛硬币让我知道这都是吓唬人的)

显然的换根$dp$,但是考场上没搞清楚贡献增减在哪里,于是本身写了一个线段树维护$set$准备优化换根

没有用上,就用这个打暴力,造成了比较奇迹的$O(qnlog^3n)$,也是没谁了

更sb的是没用$multiset$导致爆蛋蛋!!!!(大样例很水,$w_i$互不相同,就没发现不对劲)

于是这次考试垫底了。。。。

  1 #include<bits/stdc++.h>
  2 #define fo(i,x,y) for(int i=(x);i<=(y);++i)
  3 #define fr(i,x,y) for(int i=(x);i>=(y);--i)
  4 #define int long long
  5 using namespace std;
  6 inline int read(){
  7     int x=0,f=1;char ch=getchar();
  8     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
  9     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
 10     return x*f;
 11 }
 12 inline void swap_(int &a,int &b){a^=b^=a^=b;}
 13 const int NN=1e6+10,inf=1e9;
 14 int n,q,w[NN];
 15 struct SNOW{int to,next;}e[NN<<1];int head[NN],rp;
 16 inline void add(int x,int y){
 17     e[++rp]=(SNOW){y,head[x]};head[x]=rp;
 18     e[++rp]=(SNOW){x,head[y]};head[y]=rp;
 19 }
 20 int dfn[NN],rk[NN],top[NN],siz[NN],fa[NN],dep[NN],son[NN],cnt;
 21 struct SNOWtree{
 22     #define lid (id<<1)
 23     #define rid (id<<1|1)
 24     #define sit multiset<node>::iterator
 25     int ll[NN<<2],rr[NN<<2];
 26     struct node{
 27         int w; mutable int id;
 28         bool operator<(const node&a)const{return w<a.w;}
 29     };multiset<node> s[NN<<2];
 30     inline void build(int id,int l,int r){
 31         ll[id]=l;rr[id]=r; int tmp=0;
 32         for(int i=l;i<=r;++i) s[id].insert(node{w[rk[i]],0});
 33         for(auto &it:s[id]) it.id=(++tmp);
 34         if(l==r) return; int mid=(l+r)>>1;
 35         build(lid,l,mid);build(rid,mid+1,r);
 36     }
 37     inline int query(int id,int l,int r,int v){
 38         if(l<=ll[id]&&rr[id]<=r){
 39             sit pos=s[id].upper_bound(node{v,0});
 40             if(pos==s[id].end()) return 0;
 41             sit ed=s[id].end(); --ed;
 42             return ed->id-pos->id+1;
 43         }int mid=ll[id]+rr[id]>>1,ans=0;
 44         if(l<=mid) ans+=query(lid,l,r,v);
 45         if(r>mid) ans+=query(rid,l,r,v);
 46         return ans;
 47     }
 48 }tr;
 49 namespace tree_division{
 50     inline void dfs1(int f,int x){
 51         fa[x]=f; dep[x]=dep[f]+1; siz[x]=1;
 52         for(int i=head[x];i;i=e[i].next){
 53             int y=e[i].to; if(y==f) continue;
 54             dfs1(x,y); siz[x]+=siz[y];
 55             if(siz[son[x]]<siz[y]) son[x]=y;
 56         }
 57     }
 58     inline void dfs2(int x,int t){
 59         dfn[x]=++cnt; rk[cnt]=x; top[x]=t;
 60         if(son[x]) dfs2(son[x],t);
 61         for(int i=head[x];i;i=e[i].next){
 62             int y=e[i].to;
 63             if(y!=son[x]&&y!=fa[x]) dfs2(y,y);
 64         }
 65     }
 66     inline int query(int x,int y,int v){
 67         int ans=0;
 68         while(top[x]!=top[y]){
 69             if(dep[top[x]]<dep[top[y]]) swap_(x,y);
 70             ans+=tr.query(1,dfn[top[x]],dfn[x],v);
 71             x=fa[top[x]];
 72         }if(dfn[x]>dfn[y]) swap_(x,y);
 73         ans+=tr.query(1,dfn[x],dfn[y],v);
 74         return ans;
 75     }
 76 }using namespace tree_division;
 77 int dis[NN],num,an;
 78 inline void discrete(){
 79     sort(dis+1,dis+n+1); num=unique(dis+1,dis+n+1)-dis-1;
 80     for(int i=1;i<=n;++i)w[i]=lower_bound(dis+1,dis+num+1,w[i])-dis;
 81 }
 82 namespace WSN{
 83     inline short main(){
 84         // freopen("in.in","r",stdin);//freopen("bl.out","w",stdout);
 85         freopen("tears.in","r",stdin);
 86         freopen("tears.out","w",stdout);
 87         n=read(); q=read();
 88         for(int i=1;i<=n;++i) w[i]=read(),dis[i]=w[i];
 89         discrete();
 90         // for(int i=1;i<=n;i++) cout<<w[i]<<" ";cout<<endl;
 91         for(int i=1,u,v;i<n;++i){
 92             u=read(); v=read(); add(u,v);
 93         } dfs1(0,1); dfs2(1,1); tr.build(1,1,n);
 94         int root;
 95         while(q--){
 96             root=read();an=0;
 97             for(int i=1;i<=n;++i)
 98                 an+=query(root,i,w[i]);
 99             printf("%lld\n",an);
100         }
101         return 0;
102     }
103 }
104 signed main(){return WSN::main();}
TLE 25

这代码在一般$OJ$上应该是可以拿到$40$的,但是并不知道$WaitinCoders$换了界面没换测评姬。。。

于是这道题就成了卡常神题,不能用线段树,用树状数组

 

 

 1 #include<bits/stdc++.h>
 2 #define si(i,x) for(int i=head[x],y=e[i].to;i;i=e[i].next,y=e[i].to)
 3 typedef long long LL;
 4 using namespace std;
 5 namespace AE86{
 6     auto read=[](){
 7         LL x=0,f=1;char ch=getchar();
 8         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 9         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
10         return x*f;
11     };
12     auto write=[](int x,char opt='\n'){
13         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
14         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
15         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);
16     };auto swap_=[](int&a,int&b){a^=b^=a^=b;};
17 }using namespace AE86;
18 const int NN=1e6+10;
19 int n,q,w[NN],root,dis[NN],num;
20 struct SNOW{int to,next;}e[NN<<1];int head[NN],rp;
21 auto add=[](int x,int y){e[++rp]=(SNOW){y,head[x]};head[x]=rp;};
22 namespace BIT{
23     int c[NN];
24     auto update=[](int x,int v){++x;while(x<NN)c[x]+=v,x+=(x&(-x));};
25     auto query=[](int x){int ans=0;++x;while(x)ans+=c[x],x-=(x&(-x));return ans;};
26 }using namespace BIT;
27 auto discrete=[](){
28     sort(dis+1,dis+n+1);num=unique(dis+1,dis+n+1)-dis-1;
29     for(int i=1;i<=n;++i)w[i]=lower_bound(dis+1,dis+num+1,w[i])-dis;
30 };
31 LL dp[NN];int g[NN],d[NN];
32 inline void dfs(int f,int x){
33     dp[1]+=query(num)-query(w[x]);update(w[x],1);
34     si(i,x) if(y!=f) dfs(x,y); update(w[x],-1);
35 }
36 inline void prework(int f,int x){
37     d[x]-=query(w[x]-1);
38     if(f) g[x]-=query(w[f]-1);
39     update(w[x],1);
40     si(i,x) if(y!=f) prework(x,y);
41     if(f) g[x]+=query(w[f]-1);
42     d[x]+=query(w[x]-1);
43 }
44 inline void reroot(int f,int x){si(i,x) if(y!=f) dp[y]=dp[x]-g[y]-d[y]+query(w[y]-1),reroot(x,y);}
45 namespace WSN{
46     inline short main(){
47         // freopen("in.in","r",stdin);//freopen("bl.out","w",stdout);
48         freopen("tears.in","r",stdin);freopen("tears.out","w",stdout);
49         n=read();q=read();for(int i=1;i<=n;++i)dis[i]=w[i]=read();
50         for(int i=1,u,v;i<n;++i)u=read(),v=read(),add(u,v),add(v,u);
51         discrete();dfs(0,1);prework(0,1);reroot(0,1);
52         while(q--)root=read(),printf("%lld\n",dp[root]);
53         return 0;
54     }
55 }
56 signed main(){return WSN::main();}
View Code

 

T3 传统艺能

话不多说先$moBai$!!矩阵乘法带师!!

基础的有一个$dp$,$f_{ch}=\sum\limits_{i='A'}^{'C'}f_i+1$

这个东西整成向量矩阵后直接一手矩阵加速递推,$A,B,C$三种不同的转移矩阵

直接在线段树上维护他们的区间乘积即可

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 auto read=[](){
 5     int x=0,f=1;char ch=getchar();
 6     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
 8     return x*f;
 9 };
10 const int mod=998244353,NN=1e5+5;
11 int n,m;
12 char s[NN],ch[3];
13 namespace matrix{
14     struct Ma{
15         int m[4][4];
16         Ma(){memset(m,0,sizeof(m));}
17         inline void pre(){m[0][0]=m[1][1]=m[2][2]=m[3][3]=1;}
18         Ma operator*(const Ma&a)const{Ma c;
19             for(int i=0;i<4;++i)for(int j=0;j<4;++j){
20                 for(int k=0;k<4;++k)c.m[i][j]+=m[i][k]*a.m[k][j];
21                 c.m[i][j]%=mod;
22             }
23             return c;
24         }
25     }A,B,C;
26     struct Li{
27         int l[4];
28         Li(){memset(l,0,sizeof(l));}
29         Li operator*(const Ma&a)const{Li c;
30             for(int i=0;i<4;++i)for(int j=0;j<4;++j)
31                 (c.l[i]+=l[j]*a.m[i][j])%=mod;
32             return c;
33         }
34     }F;
35     auto prework=[](){
36         A.m[0][0]=A.m[0][1]=A.m[0][2]=A.m[0][3]=A.m[1][1]=A.m[2][2]=A.m[3][3]=1;
37         B.m[0][0]=B.m[1][0]=B.m[1][1]=B.m[1][2]=B.m[1][3]=B.m[2][2]=B.m[3][3]=1;
38         C.m[0][0]=C.m[1][1]=C.m[2][0]=C.m[2][1]=C.m[2][2]=C.m[2][3]=C.m[3][3]=1;
39         F.l[3]=1;
40     };
41     inline Ma get(char s){if(s=='A') return A;else if(s=='B') return B;else return C;};
42 }using namespace matrix;
43 struct SNOWtree{
44     #define lid (id<<1)
45     #define rid (id<<1|1)
46     int ll[NN<<2],rr[NN<<2]; Ma sm[NN<<2];
47     inline void pushup(int id){if(ll[id]==rr[id])return;sm[id]=sm[lid]*sm[rid];}
48     inline void build(int id,int l,int r){
49         ll[id]=l;rr[id]=r;if(l==r)return sm[id]=get(s[l]),void();
50         int mid=l+r>>1;build(lid,l,mid);build(rid,mid+1,r);pushup(id);
51     }
52     inline void update(int id,int pos,Ma g){
53         if(ll[id]==rr[id]) return sm[id]=g,void();int mid=ll[id]+rr[id]>>1;
54         if(pos<=mid)update(lid,pos,g);else update(rid,pos,g);pushup(id);
55     }
56     inline Ma query(int id,int l,int r){
57         if(l<=ll[id]&&rr[id]<=r)return sm[id];int mid=ll[id]+rr[id]>>1;Ma ans;ans.pre();
58         if(l<=mid)ans=ans*query(lid,l,r);if(r>mid)ans=ans*query(rid,l,r);return ans;
59     }
60 }tr;
61 namespace WSN{
62     inline short main(){
63         freopen("string.in","r",stdin);freopen("string.out","w",stdout);
64         n=read();m=read();scanf("%s",s+1);prework();tr.build(1,1,n);
65         while(m--){
66             int opt=read();
67             if(opt==1){int p=read();scanf("%s",ch);Ma g=get(ch[0]);tr.update(1,p,g);}
68             else{
69                 int l=read(),r=read();Li g;g=F*tr.query(1,l,r);
70                 printf("%lld\n",(g.l[0]+g.l[1]+g.l[2])%mod);
71             }
72         }
73         return 0;
74     }
75 }
76 signed main(){return WSN::main();}
View Code

 

T4 铺设道路

考场上写过第一问之后以为后两问是$dp$,于是没往贪心那里想

再看看这道题发现蛮像结论题的。。。。

 

 然后维护一个双端队列,如果是找最大值就每次从队尾找$b[l]$,反之去队首找$b[l]$

然后比比谁绝对值大给他消掉就完了,因为目的是保证最后差分为$0$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 auto read=[](){
 5     int x=0,f=1;char ch=getchar();
 6     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
 8     return x*f;
 9 };
10 auto max_=[](int a,int b){return a>b?a:b;};
11 const int mod=1e9+7,NN=3e5+5,inf=1e18;
12 int n,d[NN],b[NN],day,ans1,ans2;
13 deque<int>q;
14 namespace WSN{
15     inline short main(){
16         freopen("road.in","r",stdin);freopen("road.out","w",stdout);
17         n=read();for(int i=1;i<=n;++i)d[i]=read(),b[i]=d[i]-d[i-1],day+=max_(b[i],0);
18         ++n;b[n]=-d[n-1];
19         for(int i=1,u,pw;i<=n;++i)
20             if(b[i]>0) q.push_back(i);
21             else while(b[i]){
22                 u=q.back(),pw=pow(i-u,2);pw%=mod;
23                 if(abs(b[i])>=abs(b[u])) q.pop_back(),ans1=(ans1+pw*b[u]%mod)%mod,b[i]+=b[u],b[u]=0;
24                 else ans1=(ans1+pw*(-b[i])%mod)%mod,b[u]+=b[i],b[i]=0;
25             }
26         q.clear();for(int i=1;i<=n;++i) b[i]=d[i]-d[i-1];
27         for(int i=1,u,pw;i<=n;++i)
28             if(b[i]>0) q.push_back(i);
29             else while(b[i]){
30                 u=q.front(),pw=pow(i-u,2);pw%=mod;
31                 if(abs(b[i])>=abs(b[u])) q.pop_front(),ans2=(ans2+pw*b[u]%mod)%mod,b[i]+=b[u],b[u]=0;
32                 else ans2=(ans2+pw*(-b[i])%mod)%mod,b[u]+=b[i],b[i]=0;
33             }
34         printf("%lld\n%lld\n%lld\n",day,ans1,ans2);
35         return 0;
36     }
37 }
38 signed main(){return WSN::main();}
View Code

 

这次题还是确实不算难的,挂的话就是挂在那个$multiset$,以后一定要注意数组元素重复的问题,记得上次的那个自然数$mex$

就是没有考虑重复的情况,还是要细心。。。。

posted @ 2021-10-26 19:10  雪域亡魂  阅读(77)  评论(0编辑  收藏  举报