[考试反思]0516省选模拟98:等待

前两个是同一道题合计$100pts$。然后我个弱智没写快读被卡常丢了$40$。

(就算改成scanf("%s")然后再去模拟进制都能$AC$,原理不明,只是读整数太慢了)

看到这套题感觉题目看起来特别麻烦然后就怂了,大概是在摸鱼。

前一两个小时可能都没怎么动脑子(麻木),然后回过神来发现$T1$好像没有想象中那么恶心。

但是感觉复杂度好像不太对,也没想啥反正就是交上去了。

然后继续摸鱼。

尝试想$T3$来着。但是脑子动不起来,于是打$10pts$跑路。$T2$会$10pts$但是好像挺麻烦

所以嫌少就直接扔掉了。。。

状态又变差了。。。可能是想放个假。。。或者开个学

 

T1:Bohemian Rhapsody

大意:维护$m$棵树,每棵树最开始都一样,支持操作:把第$[l,r]$棵树上$(u,v)$路径的所有边长度改为$0$。

所有操作结束后,询问每棵树的 所有点对距离和。$n,m,q \le 5 \times 10^5$

同时对多棵树搞什么操作很麻烦就算是$O(1)$复杂度也不对。考虑差分(也就是扫描线)那么增量的个数是有限的。

树剖线段树维护$size_u \times (n-size_u)$。支持区间打置零标记以及删除一层标记。随便写。$O(nlog^2n)$

使用$LCT$可以做到$O(nlogn)$(说着轻巧。。)

继续$\mod$开鸽的$fread$板子。

 1 #include<cstdio>
 2 #include<vector>
 3 using namespace std;
 4 const int mod=1000000007,S=500005;
 5 char IN[1<<26],*p=IN;
 6 int mo(int a){return a>=mod?a-mod:a;}
 7 int n,m,q,f[S],dep[S],sz[S],top[S],dfn[S],tim,son[S],fir[S],l[S<<1],to[S<<1],ec,ans,w[S],tot[S<<2],tag[S<<2];
 8 void link(int a,int b){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;}
 9 void in(int&x){x=0;while(*p<48||*p>57)p++;while(*p>47&&*p<58)x=x*10+*p++-48;}
10 void dfs(int p,int fa){
11     sz[p]=1; f[p]=fa; dep[p]=dep[fa]+1;
12     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
13         dfs(to[i],p); sz[p]+=sz[to[i]];
14         if(sz[to[i]]>sz[son[p]])son[p]=to[i];
15     }
16 }
17 void DFS(int p,int tp){
18     top[p]=tp; dfn[p]=++tim; top[p]=tp;
19     if(son[p])DFS(son[p],tp);
20     for(int i=fir[p];i;i=l[i])if(!dfn[to[i]])DFS(to[i],to[i]);
21     for(int i=fir[p];i;i=l[i])if(to[i]!=f[p])w[dfn[to[i]]]=1ll*sz[to[i]]*(n-sz[to[i]])%mod;
22 }
23 #define lc p<<1
24 #define rc lc|1
25 #define md (L+R>>1)
26 void up(int p,int L,int R){tot[p]=tag[p]?0:(L==R?w[L]:mo(tot[lc]+tot[rc]));}
27 void build(int p,int L,int R){
28     if(L==R){tot[p]=w[L];return;}
29     build(lc,L,md);build(rc,md+1,R); up(p,L,R);
30 }
31 void add(int l,int r,int v,int p=1,int L=1,int R=n){
32     if(l<=L&&R<=r)return tag[p]+=v,up(p,L,R);
33     if(l<=md)add(l,r,v,lc,L,md); if(r>md)add(l,r,v,rc,md+1,R); up(p,L,R);
34 }
35 void upd(int x,int y,int o){
36     while(top[x]!=top[y]){
37         if(dep[top[x]]<dep[top[y]])x^=y^=x^=y;
38         add(dfn[top[x]],dfn[x],o);x=f[top[x]];
39     }if(dfn[x]>dfn[y])x^=y^=x^=y;
40     if(x!=y)add(dfn[x]+1,dfn[y],o);
41 }
42 vector<int>x[S],y[S],o[S];
43 #define pb push_back
44 int main(){
45     fread(IN,1,1<<26,stdin);
46     in(n);in(m);in(q);
47     for(int i=1,a,b;i<n;++i)in(a),in(b),link(a,b),link(b,a);
48     dfs(1,0);DFS(1,1);build(1,1,n);
49     for(int i=1,a,b,u,v;i<=q;++i)in(a),in(b),in(u),in(v),
50         x[a].pb(u),y[a].pb(v),o[a].pb(1),b++,x[b].pb(u),y[b].pb(v),o[b].pb(-1);
51     for(int i=1,r=1;i<=m;++i){
52         for(int j=0;j<x[i].size();++j)upd(x[i][j],y[i][j],o[i][j]);
53         ans=(ans+1ll*(r=r*12345678ll%mod)*tot[1])%mod;
54     }printf("%d\n",ans);
55 }
View Code

 

T2:Under Pressure

题如其名。狗屁题。

因为思路完全不着边际所以丝毫没有改的欲望。

 

T3:Radio Ga Ga

大意:有$m$个任务,要求你恰好在$t_i$时刻达到点$x_i$,奖励为$w_i$。如果你已经走过的区间是$[l,r]$那么你下一时刻可以走到$l-1$或$r+1$。

$n$时刻恰好走完$[1,n]$。多次询问如果你的初始区间是$[s_i,s_i]$那么你获得的最大奖励是多少。$n\le 10^9,m,q \le 5 \times 10^5$

暴力$dp$的话,就是记录一下这$m$个任务对应的$2m$个区间(标记最后经过的点是左端点还是右端点)

转移数级别是$m^2$的。优化一下。

首先我们考虑从较大的区间转移到较小的区间,应该是包含关系。

那么左端点排序之后,右端点应该递减。扫描线加一些数据结构。

为了处理特殊情况这里的排序很神奇:左端点升序,然后如果最后经过的点是有端点则优先,在否则如果是右端点则按长度降序,否则升序。

只要分一大堆情况讨论就发现$AKT$成功解决了所有转移的边界限制。需要特殊处理的是如果限制的是右端点则插入数据结构的时候右端点要$-1$。

然后数据结构可以直接动态开点线段树也可以直接离散化+树状数组。

然后你就处理出了每个区间的$dp$值。对于每个询问只要找到包含它区间的最大$dp$值就可以了。

可以再来一个线段树,也可以离线扫描线+可删堆。注意如果限制的是左右端点则初始位置就不能是那个。同时还要考虑到长度为$1$的区间。

我就是懒得写线段树了。反正复杂度都是$O(nlogn)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define S 3333333
 4 #define ll long long
 5 int n,q,m,r[S],rc,pc;ll t[S],ans[S];
 6 unordered_map<int,ll>ex;
 7 struct P{int l,r,w,o;ll dp;}p[S];
 8 struct Qs{int x,o;}qs[S];
 9 void add(int p,ll v){for(;p;p^=p&-p)t[p]=max(t[p],v);}
10 ll ask(int p,ll a=0){for(;p<rc;p+=p&-p)a=max(a,t[p]);return a;}
11 vector<ll>v[S],V[S]; priority_queue<ll>Q,D;
12 ll top(){while(D.size()&&D.top()==Q.top())D.pop(),Q.pop();return Q.size()?Q.top():0;}
13 void lsh(int x){r[++rc]=x;r[++rc]=x-1;r[++rc]=x+1;}
14 int main(){
15     scanf("%d%d%d",&n,&m,&q);
16     for(int i=1,k,x,w;i<=m;++i){
17         scanf("%d%d%d",&k,&x,&w); lsh(x); if(k==1){ex[x]=w;continue;}
18         if(x+k-1<=n)lsh(x+k-1),p[++pc]=(P){x,x+k-1,w,0};
19         if(x-k+1>=1)lsh(x-k+1),p[++pc]=(P){x-k+1,x,w,1};
20     }
21     sort(r+1,r+1+rc); rc=unique(r+1,r+1+rc)-r; r[rc]=n+1;
22     for(int i=1;i<=pc;++i)p[i].l=lower_bound(r+1,r+rc,p[i].l)-r,p[i].r=lower_bound(r+1,r+rc,p[i].r)-r;
23     sort(p+1,p+1+pc,[](P x,P y){return x.l^y.l?x.l<y.l:(x.o^y.o?x.o>y.o:x.o^x.r-x.l<y.r-y.l);});
24     for(int i=1;i<=pc;++i)v[p[i].r+1-p[i].o].push_back(p[i].dp=ask(p[i].r)+p[i].w),V[p[i].l+1-p[i].o].push_back(p[i].dp),add(p[i].r-p[i].o,p[i].dp);
25     for(int i=1;i<=q;++i)scanf("%d",&qs[i].x),qs[i].o=i;
26     sort(qs+1,qs+1+q,[](Qs x,Qs y){return x.x<y.x;});
27     int pt=1;
28     while(pt<=q&&qs[pt].x<r[1])pt++;
29     for(int i=1;i<rc;++i){
30         for(int j=0;j<V[i].size();++j)Q.push(V[i][j]);
31         for(int j=0;j<v[i].size();++j)D.push(v[i][j]);
32         while(pt<=q&&qs[pt].x<r[i+1])ans[qs[pt].o]=top()+ex[qs[pt].x],pt++;
33     }for(int i=1;i<=q;++i)printf("%lld\n",ans[i]);
34 }
View Code

 

posted @ 2020-05-16 20:31  DeepinC  阅读(291)  评论(0编辑  收藏  举报