1. 程式人生 > 其它 >2021.7.29考試總結[NOIP模擬27]

2021.7.29考試總結[NOIP模擬27]

T1牛半仙的妹子圖 T2牛半仙的妹子tree T3牛半仙的妹子序列

T1 牛半仙的妹子圖


做法挺多的,可以最小生成樹或者最短路,複雜度O(cq),c是顏色數。

我考場上想到了原來做過的一道題影子,就用了並查集,把邊權排序後一個個插入,記錄權值的字首和,複雜度mlogm挺優秀。

後來發現wlr都是1e9,一個個求字首和直接炸了,考場上感覺l,r,w差值對答案有影響就沒離散化,開了個map記出現的w的字首和,其他都能O1計算。

這不切了嗎?年輕的我如是想到。

於是我領略到了map80倍常數的威力。離散化開陣列再帶到初值計算就A了。

考場拿了75pts還WA了仨點,據WTZ說要大力分類討論,但我改對離散化直接切了,不大懂。

code:

 1 #include<bits/stdc++.h>
 2
#define debug exit(0) 3 #define int long long 4 #define rin register signed 5 using namespace std; 6 const int NN=5e5+5; 7 struct edge{ 8 int st,to,nex,w; 9 }e[NN]; 10 struct bcj{ 11 int fa; 12 bitset<650>gl; 13 }p[NN]; 14 int n,m,q,x,M,opt,head[NN],num,c[NN],ans,maxr,l[10005],r[10005
]; 15 int has[NN],ext,pre[NN],ts[NN]; 16 inline bool cmp(edge a,edge b){ return a.w<b.w; } 17 inline int getfa(int a){ return p[a].fa==a?a:p[a].fa=getfa(p[a].fa); } 18 inline int read(){ 19 int x=0,f=1; 20 char ch=getchar(); 21 while(ch<'0'||ch>'9'){ 22 if(ch=='-') f=-1; 23
ch=getchar(); 24 } 25 while(ch>='0'&&ch<='9'){ 26 x=(x<<1)+(x<<3)+(ch^48); 27 ch=getchar(); 28 } 29 return x*f; 30 } 31 void write(int x){ 32 if(x<0) putchar('-'), x=-x; 33 if(x>9) write(x/10); 34 putchar(x%10+'0'); 35 } 36 void lsh(){ 37 for(int i=1;i<=m;i++) has[i]=e[i].w; 38 ext=unique(has+1,has+1+m)-has-1; 39 for(int i=1;i<=m;i++) 40 e[i].w=lower_bound(has+1,has+ext+1,e[i].w)-has; 41 } 42 inline void add(int a,int b,int d){ 43 e[++num].to=b; e[num].nex=head[a]; head[a]=num; e[num].w=d; e[num].st=a; 44 } 45 void gather(int a,int b){ 46 a=getfa(a); b=getfa(b); 47 if(a==b) return; 48 p[b].fa=a; p[a].gl|=p[b].gl; 49 } 50 signed main(){ 51 n=read(); m=read(); q=read(); x=read(); opt=read(); ts[0]=1; 52 if(opt) M=read(); 53 for(rin i=1;i<=n;i++){ 54 c[i]=read(); 55 p[i].fa=i; p[i].gl[c[i]]=1; 56 } 57 for(rin i=1;i<=m;i++){ 58 int u=read(),v=read(),w=read(); 59 add(u,v,w); 60 } sort(e+1,e+m+1,cmp); 61 lsh(); 62 for(rin i=1;i<=m;i++){ 63 int u=e[i].st,v=e[i].to; 64 gather(u,v); 65 if(e[i].w!=e[i+1].w){ 66 ts[e[i].w]=p[getfa(x)].gl.count(); 67 pre[e[i].w]=pre[e[i].w-1]+ts[e[i].w-1]*(has[e[i].w]-has[e[i].w-1]-1); 68 pre[e[i].w]+=ts[e[i].w]; 69 } 70 } 71 for(rin i=1;i<=q;i++){ 72 int l=read(),r=read(); 73 if(opt) l=(l^ans)%M+1, r=(r^ans)%M+1; 74 if(l>r) swap(l,r); l--; 75 int wl=upper_bound(has,has+ext+1,l)-has-1; 76 int wr=upper_bound(has,has+ext+1,r)-has-1; 77 ans=pre[wr]+ts[wr]*(r-has[wr]); 78 ans-=pre[wl]+ts[wl]*(l-has[wl]); 79 write(ans); putchar('\n'); 80 } 81 return 0; 82 }
T1

T2 牛半仙的妹子tree


考場暴力炸了,只有10pts。

題解里正解好像是分塊,好像還能點分樹,機房裡還看到了很多奇奇怪怪的AC程式碼,

但最快的竟然是求LCA暴力判斷就離譜。

記錄染色的點和染色的時間,查詢時列舉比較時間差和距離即可。

樹剖竟然只400多ms?

code:

 1 #include<bits/stdc++.h>
 2 #define debug exit(0)
 3 #define ii pair<int,int>
 4 #define mp make_pair
 5 #define fi first
 6 #define se second
 7 #define pb push_back
 8 using namespace std;
 9 const int NN=1e5+5;
10 int n,m,x,to[NN<<1],nex[NN<<1],head[NN],opt,num;
11 int dep[NN],son[NN],siz[NN],dfn[NN],id[NN],fa[NN],top[NN],cnt;
12 vector<ii>t;
13 inline int read(){
14     int x=0,f=1;
15     char ch=getchar();
16     while(ch<'0'||ch>'9'){
17         if(ch=='-') f=-1;
18         ch=getchar();
19     }
20     while(ch>='0'&&ch<='9'){
21         x=(x<<1)+(x<<3)+(ch^48);
22         ch=getchar();
23     }
24     return x*f;
25 }
26 void write(int x){
27     if(x<0) putchar('-'), x=-x;
28     if(x>9) write(x/10);
29     putchar(x%10+'0');
30 }
31 inline void add(int a,int b){
32     to[++num]=b; nex[num]=head[a]; head[a]=num;
33     to[++num]=a; nex[num]=head[b]; head[b]=num;
34 }
35 void dfs1(int f,int s){
36     fa[s]=f; dep[s]=dep[f]+1; siz[s]=1;
37     for(int i=head[s];i;i=nex[i]){
38         int v=to[i];
39         if(v==f) continue;
40         dfs1(s,v);
41         siz[s]+=siz[v];
42         if(siz[v]>siz[son[s]]) son[s]=v;
43     }
44 }
45 void dfs2(int s,int t){
46     top[s]=t; dfn[s]=++cnt; id[cnt]=s;
47     if(!son[s]) return;
48     dfs2(son[s],t);
49     for(int i=head[s];i;i=nex[i]){
50         int v=to[i];
51         if(v!=son[s]&&v!=fa[s]) dfs2(v,v);
52     }
53 }
54 inline int LCA(int x,int y){
55     int fx=top[x],fy=top[y];
56     while(fx!=fy)
57         if(dep[fx]<dep[fy]) y=fa[fy], fy=top[y];
58         else x=fa[fx], fx=top[x];
59     return dep[x]>dep[y]?y:x;
60 }
61 inline bool check(int x,int ti){
62     for(int j=0;j<t.size();j++)
63         if(dep[x]+dep[t[j].fi]-2*dep[LCA(x,t[j].fi)]<=ti-t[j].se)
64             return 0;
65     return 1;
66 }
67 signed main(){
68     n=read(); m=read();
69     for(int i=1;i<n;i++) add(read(),read());
70     dfs1(0,1); dfs2(1,1);
71     for(int i=1;i<=m;i++){
72         opt=read(); x=read();
73         if(opt==1) if(check(x,i)) t.pb(mp(x,i));
74         if(opt==2) t.clear();
75         if(opt==3) puts(check(x,i)?"orzFsYo":"wrxcsd");
76     }
77     return 0;
78 }
T2

T3 牛半仙的妹子序列


一眼極長上升子序列。

但不會。

於是又回顧了一遍god knows(模擬16),還是不大懂,整了挺久。但好像幾乎一模一樣。

把求最小權的步驟換成求方案數就完了。

code:

 1 #include<bits/stdc++.h>
 2 #define debug exit(0)
 3 #define int long long
 4 #define ld rt<<1
 5 #define rd (rt<<1)|1
 6 using namespace std;
 7 const int p=998244353,NN=2e5+5;
 8 int n,bty[NN],ans;
 9 inline int read(){
10     int x=0,f=1;
11     char ch=getchar();
12     while(ch<'0'||ch>'9'){
13         if(ch=='-') f=-1;
14         ch=getchar();
15     }
16     while(ch>='0'&&ch<='9'){
17         x=(x<<1)+(x<<3)+(ch^48);
18         ch=getchar();
19     }
20     return x*f;
21 }
22 void write(int x){
23     if(x<0) putchar('-'), x=-x;
24     if(x>9) write(x/10);
25     putchar(x%10+'0');
26 }
27 struct segment_tree{
28     int mx[NN<<2],sum[NN<<2],l[NN<<2],r[NN<<2],us[NN<<2],nxt;
29     int calc(int rt,int val){
30         if(l[rt]==r[rt]) return mx[rt]>val?sum[rt]:0;
31         if(mx[rd]<=val) return calc(ld,val);
32         return (us[ld]+calc(rd,val))%p;
33     }
34     void pushup(int rt){
35         mx[rt]=max(mx[ld],mx[rd]);
36         sum[rt]=(sum[rd]+(us[ld]=calc(ld,mx[rd])))%p;
37     }
38     void build(int rt,int opl,int opr){
39         l[rt]=opl; r[rt]=opr; mx[rt]=-1;
40         if(opl==opr) return;
41         int mid=opl+opr>>1;
42         build(ld,opl,mid);
43         build(rd,mid+1,opr);
44     }
45     void insert(int rt,int pos,int i,int val){
46         if(l[rt]==r[rt]){ sum[rt]=val; mx[rt]=i; return; }
47         int mid=l[rt]+r[rt]>>1;
48         if(pos<=mid) insert(ld,pos,i,val);
49         else insert(rd,pos,i,val);
50         pushup(rt);
51     }
52     int query(int rt,int opl,int opr){
53         if(l[rt]>=opl&&r[rt]<=opr){
54             int ans=calc(rt,nxt);
55             nxt=max(nxt,mx[rt]);
56             return ans;
57         }
58         int mid=l[rt]+r[rt]>>1,ans=0;
59         if(opr>mid) (ans+=query(rd,opl,opr))%=p;
60         if(opl<=mid) (ans+=query(ld,opl,opr))%=p;
61         return ans;
62     }
63 }s;
64 signed main(){
65     n=read();
66     for(int i=1;i<=n;i++) bty[i]=read();
67     ++n; bty[n]=n; s.build(1,0,n); s.insert(1,0,0,0);
68     for(int i=1;i<=n;i++){ 
69         s.nxt=-1;
70         int tmp=s.query(1,0,bty[i]-1)%p;
71         if(!tmp) tmp=1; 
72         s.insert(1,bty[i],i,tmp);
73         if(i==n) write(tmp), putchar('\n');
74     }
75     return 0;
76 }
T3