C2 Guessing the Greatest (二分+构造)

题目大意:交互题,每次可以询问一个子区间次大值的位置,最多询问20次,问全局最大值的位置。n=1e5

40次的情况大力二分,20次需要一些技巧

设全局最大值位置为$x$

问一次全局次大值,设为$pos$,再次询问$pos$两侧判断最大值在$pos$左侧还是右侧,并把$pos$它放在后续处理区间的头或者尾

放在头/尾可以减少很多麻烦

现假设$pos$在尾,我们在$[1,pos-1]$里找$x$

每次二分一个位置$mid$,如果$mid\le x$,那么问$[mid,pos]$结果是$pos$,如果$mid>x$,结果不是$pos$

如此可找到x

 1 const int N1=105; const int inf=0x3f3f3f3f;
2
3 int n,now;
4 int getx(int l,int r)
5 {
6 if(l==r) return 0;
7 printf("? %d %d\n",l,r);
8 fflush(stdout);
9 int x; scanf("%d",&x); return x;
10 }
11 void solveL(int pos)
12 {
13 int l=1,r=pos-1,mid,ans=0,k;
14 while(l<=r)
15 {
16 mid=(l+r)>>1;
17 k=getx(mid,pos);
18 if(k==pos) ans=mid, l=mid+1;
19 else r=mid-1;
20 }
21 printf("! %d\n",ans); exit(0);
22 }
23 void solveR(int pos)
24 {
25 int l=pos+1,r=n,mid,ans=0,k;
26 while(l<=r)
27 {
28 mid=(l+r)>>1;
29 k=getx(pos,mid);
30 if(k==pos) ans=mid, r=mid-1;
31 else l=mid+1;
32 }
33 printf("! %d\n",ans); exit(0);
34 }
35
36 int main()
37 {
38 scanf("%d",&n);
39 int pos=getx(1,n),k;
40 if(pos==1) solveR(1);
41 else if(pos==n) solveL(n);
42 else{
43 k=getx(1,pos);
44 if(k==pos) solveL(pos); else solveR(pos);
45 }
46 return 0;
47 }

Max Median (二分+数据结构)(中位数问题)

题目大意:给出一个序列,问所有长度大于等于k的子区间中,中位数的最大值是多少,$n=2e5$

题解给了这样一个妙妙思路:

首先考虑序列都是1和-1咋做:权值和大于0的子区间的中位数是1!需要维护小于某个值的最小位置,树状数组记录前缀最小值

推广到中位数问题,二分。

每次判断中位数$\ge mid$是否可行

把小于$mid$填成-1,$\ge mid$填成1,权值和大于0的子区间的中位数$\ge mid$!和上面同样的方法做就行了

 1 const int N1=400010; const int inf=0x3f3f3f3f;
2
3 int n,K,nn;
4 int a[N1],sum[N1];
5 struct bit{
6 int mi[N1];
7 void upd(int x,int w)
8 { for(int i=x;i<=nn;i+=i&(-i)) mi[i]=min(mi[i],w); }
9 int query(int x)
10 { int ans=inf; for(int i=x;i;i-=i&(-i)) ans=min(ans,mi[i]); return ans; }
11 void clr(int x)
12 { for(int i=x;i<=nn;i+=i&(-i)) mi[i]=inf; }
13 }s;
14 int check(int w)
15 {
16 memset(s.mi,0x3f,sizeof(s.mi));
17 s.upd(n+1+0,0);
18 for(int i=1,j;i<=n;i++)
19 {
20 if(a[i]<w) sum[i]=sum[i-1]-1; else sum[i]=sum[i-1]+1;
21 j=s.query(n+1+sum[i]-1);
22 if(i-j>=K) return 1;
23 s.upd(n+1+sum[i],i);
24 }
25 return 0;
26 }
27
28 int main()
29 {
30 scanf("%d%d",&n,&K); nn=n+n+1;
31 for(int i=1;i<=n;i++) scanf("%d",&a[i]);
32 int l=1,r=n,ans=0,mid;
33 while(l<=r)
34 {
35 mid=(l+r)>>1;
36 if(check(mid)) ans=mid, l=mid+1;
37 else r=mid-1;
38 }
39 printf("%d\n",ans);
40 return 0;
41 }

Paired Payment (图上构造)

题目大意:给一个无向图,每次必须连着走两条边,代价为$(w1+w2)^{2}$,问从1走到其它所有点的代价最小值,$n=1e5,w\le 50$

又是一道构造妙妙题目

由于$w$很小,考虑拆点

对于一条有向边$(u,v,w)$

i是和v相连的出来的所有不同权值,$u->(v,i)$,代价$(w+i)^{2}$。 $ (u,w)->v$,代价0

考虑连着走两条边$(x,y,w1)(y,z,w2)$的情形:$x->(y,w2)->z$ 代价为$(w1+w2)^{2}$

然后最短路就行了,边数为$O(Wm)$,时间复杂度$O(Wmlogm)$

用map维护拆点可以减少点数

 1 #define ite map<int,int>::iterator
2 const int N1=500005; const int M1=N1*42; const ll inf=0x3f3f3f3f3f3f3f3fll;
3
4 struct edge{
5 int to[M1],nxt[M1],val[M1],head[N1],cte;
6 int ae(int u,int v,int w)
7 { cte++; to[cte]=v, nxt[cte]=head[u]; head[u]=cte; val[cte]=w; }
8 // printf("%d %d %d\n",u,v,w);
9 }e;
10 struct node{
11 int id; ll val;
12 friend bool operator < (const node &s1,const node &s2)
13 { return s1.val>s2.val; }
14 };
15 priority_queue<node>que;
16
17 int n,m,tot;
18 int id[N1]; ll dis[N1]; bool vis[N1];
19 map<int,int>mp[N1];
20 void addmp(int u,int v,int w)
21 {
22 ite k=mp[v].find(w); int y;
23 if(k==mp[v].end()) y=++tot, mp[v][w]=tot;
24 else y=(*k).second;
25 e.ae(y,u,0);
26 }
27 void adde(int u,int v,int w1)
28 {
29 int y,w2;
30 for(ite k=mp[v].begin();k!=mp[v].end();k++)
31 {
32 w2=(*k).first; y=(*k).second;
33 e.ae(u,y,(w1+w2)*(w1+w2));
34 }
35 }
36 void dijkstra()
37 {
38 int x,j,v; node tmp;
39 memset(dis,0x3f,sizeof(dis));
40 que.push((node){1,0}); dis[1]=0;
41 while(!que.empty())
42 {
43 tmp=que.top(); que.pop(); x=tmp.id;
44 if(vis[x]) continue; vis[x]=true;
45 for(j=e.head[x];j;j=e.nxt[j])
46 {
47 v=e.to[j];
48 if(dis[v]>dis[x]+e.val[j])
49 {
50 dis[v]=dis[x]+e.val[j];
51 que.push((node){v,dis[v]});
52 }
53 }
54 }
55 }
56 int ex[N1],ey[N1],ew[N1];
57
58 int main()
59 {
60 scanf("%d%d",&n,&m);
61 tot=n;
62 for(int i=1;i<=m;i++)
63 {
64 scanf("%d%d%d",&ex[i],&ey[i],&ew[i]);
65 addmp(ex[i],ey[i],ew[i]); addmp(ey[i],ex[i],ew[i]);
66 }
67 for(int i=1;i<=m;i++)
68 {
69 adde(ex[i],ey[i],ew[i]); adde(ey[i],ex[i],ew[i]);
70 }
71 dijkstra();
72 for(int i=1;i<=n;i++)
73 if(dis[i]<inf) printf("%lld ",dis[i]);
74 else printf("-1 ");
75 puts("");
76 return 0;
77 }

Pairs of Paths (树上计数)

题目大意:给一棵n个点的树,给出m条链,问有多少对链,相交部分只有一个点。$n,m=3e5$

考虑讨论交点情况

设两个链的$LCA$分别为$fx,fy$,唯一的交点为$p$

如果$p\ne fx$且$p\ne fy$,这种情况不存在!画一下图就能发现了,不可能交出来一个X字型

如果$p=fx$,我们把$x$这条链的贡献放到$y$里统计

如果$p=fx=fy$,我们在$p$点讨论贡献

离线每条链到树上,在端点和$LCA$统计贡献

记录$f[x]$表示以$x$点为$LCA$的链条数

$g[x]$表示以$father[x]$为$LCA$时,经过$x$点的链数。那么在$x$点统计链端点的贡献时,肯定得把$g[x]$这部分去掉,因此我们维护一个$h[x]$表示到根节点链上所有点的$f[x]-g[x]$,再记录$h[x]$的前缀和

还有一些链向下有两个端点,只减$g[x]$会导致去掉了两次贡献,需要容斥一下把它们加回来一次,用$map$维护

在$x$点统计链$LCA$的贡献时,$f[x]-1$就是贡献,最后把这部分贡献/2就行

  1 const int N1=300005; const ll p=998244353;
2
3 ll qpow(ll x,ll y)
4 {
5 ll ans=1;
6 for(;y;x=x*x%p,y>>=1) if(y&1) ans=ans*x%p;
7 return ans;
8 }
9 struct EDGE{
10 int to[N1*2],nxt[N1*2],head[N1],cte;
11 void ae(int u,int v)
12 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; }
13 }e;
14
15 int n,m;
16 int ff[N1][20],dep[N1];
17 struct node{
18 int x,y;
19 friend bool operator < (const node &s1,const node &s2)
20 {
21 if(s1.x!=s2.x) return s1.x<s2.x;
22 return s1.y<s2.y;
23 }
24 };
25
26 void dfs0(int u)
27 {
28 for(int j=e.head[u];j;j=e.nxt[j])
29 {
30 int v=e.to[j]; if(v==ff[u][0]) continue;
31 ff[v][0]=u; dep[v]=dep[u]+1; dfs0(v);
32 }
33 }
34 void getfa()
35 {
36 for(int j=1;j<=19;j++)
37 for(int i=1;i<=n;i++)
38 ff[i][j]=ff[ ff[i][j-1] ][j-1];
39 }
40 int LCA(int x,int y)
41 {
42 if(dep[x]<dep[y]) swap(x,y);
43 for(int j=19;j>=0;j--) if(dep[ff[x][j]]>=dep[y]) x=ff[x][j];
44 if(x==y) return x;
45 int ans=0;
46 for(int j=19;j>=0;j--)
47 {
48 if(ff[x][j]==ff[y][j]) ans=ff[x][j];
49 else x=ff[x][j], y=ff[y][j];
50 }
51 return ans;
52 }
53 int jump(int x,int d)
54 {
55 for(int j=19;j>=0;j--) if(dep[ff[x][j]]>=d)
56 x=ff[x][j];
57 return x;
58 }
59
60 struct PATH{
61 int x,y,fa,fx,fy;
62 }pa[N1];
63 ll f[N1],g[N1];
64 ll h[N1],sh[N1];
65 vector<int>qp[N1],ql[N1];
66 map<node,int>two;
67
68 ll ans1,ans2;
69 void calc_lca(int u)
70 {
71 int x,y,fa,fx,fy;
72 for(int k=0;k<ql[u].size();k++)
73 {
74 int i=ql[u][k];
75 x=pa[i].x, y=pa[i].y, fa=pa[i].fa, fx=pa[i].fx, fy=pa[i].fy;
76 if(x==y){
77 ans2+=f[u]-1;
78 }else if(fa==y){
79 ans2+=f[u]-g[fx];
80 }else{
81 ans2+=f[u]-g[fx]-g[fy]+two[(node){fx,fy}];
82 }
83 }
84 }
85 void calc_nlca(int u)
86 {
87 h[u]=f[u]; sh[u]=sh[ff[u][0]]+h[u];
88 int x,y,fa,fx,fy;
89 for(int k=0;k<qp[u].size();k++)
90 {
91 int i=qp[u][k];
92 fa=pa[i].fa;
93 ans1+=sh[u]-sh[fa];
94 }
95 }
96 void dfs1(int u)
97 {
98 calc_lca(u);
99 calc_nlca(u);
100 for(int j=e.head[u];j;j=e.nxt[j])
101 {
102 int v=e.to[j]; if(v==ff[u][0]) continue;
103 h[u]=f[u]-g[v]; sh[u]=sh[ff[u][0]]+h[u];
104 dfs1(v);
105 }
106 }
107
108 int main()
109 {
110 scanf("%d",&n);
111 int x,y,fa,fx,fy;
112 for(int i=1;i<n;i++) scanf("%d%d",&x,&y), e.ae(x,y), e.ae(y,x);
113 dep[1]=1; dfs0(1); getfa();
114 scanf("%d",&m);
115 for(int i=1;i<=m;i++)
116 {
117 scanf("%d%d",&x,&y);
118 fa=LCA(x,y);
119 if(x==y){
120 f[x]++; fx=fy=0;
121 ql[x].push_back(i);
122 }else if(fa==x||fa==y){
123 if(fa==x) swap(x,y);
124 fx=jump(x,dep[fa]+1); fy=0;
125 f[fa]++; g[fx]++;
126 qp[x].push_back(i); ql[fa].push_back(i);
127 }else{
128 fx=jump(x,dep[fa]+1); fy=jump(y,dep[fa]+1);
129 if(fx>fy) swap(x,y), swap(fx,fy);
130 f[fa]++; g[fx]++; g[fy]++; two[(node){fx,fy}]++;
131 qp[x].push_back(i); qp[y].push_back(i); ql[fa].push_back(i);
132 }
133 pa[i].x=x, pa[i].y=y, pa[i].fa=fa, pa[i].fx=fx, pa[i].fy=fy;
134 }
135 dfs1(1); ans1=ans1+ ans2/2;
136 printf("%lld\n",ans1);
137 return 0;
138 }

CF1486X Codeforces Round #703的更多相关文章

  1. Codeforces Round #703 (Div. 2)__ B. Eastern Exhibition__ 纯纯的思维

    原题链接https://codeforces.com/contest/1486/problem/B 题目 解题思路 这是个思维题,  算是货仓选址的变式, 想要到达各个点距离最小,我们的目标可以化为先 ...

  2. Codeforces Round #703 (Div. 2) (A~E)

    A. Shifting Stacks 题目链接 点我跳转 题目大意 给定 \(N\) 个土堆,第 \(i\) 个土堆有 \(Ai\) 个木块 你可以将第 \(i\) 个土堆的木块转移至第 \(i + ...

  3. Codeforces Round #366 (Div. 2) ABC

    Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...

  4. Codeforces Round #354 (Div. 2) ABCD

    Codeforces Round #354 (Div. 2) Problems     # Name     A Nicholas and Permutation standard input/out ...

  5. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  6. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  7. Codeforces Round #279 (Div. 2) ABCDE

    Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems     # Name     A Team Olympiad standard input/outpu ...

  8. Codeforces Round #262 (Div. 2) 1003

    Codeforces Round #262 (Div. 2) 1003 C. Present time limit per test 2 seconds memory limit per test 2 ...

  9. Codeforces Round #262 (Div. 2) 1004

    Codeforces Round #262 (Div. 2) 1004 D. Little Victor and Set time limit per test 1 second memory lim ...

随机推荐

  1. Solution -「ARC 058C」「AT 1975」Iroha and Haiku

    \(\mathcal{Description}\)   Link.   称一个正整数序列为"俳(pái)句",当且仅当序列中存在连续一段和为 \(x\),紧接着连续一段和为 \(y ...

  2. Solution -「LGR-087」「洛谷 P6860」象棋与马

    \(\mathcal{Description}\)   Link.   在一个 \(\mathbb R^2\) 的 \((0,0)\) 处有一颗棋子,对于参数 \(a,b\),若它当前坐标为 \((x ...

  3. linux下gdb如何处理coredump错误

    linux下gdb如何处理coredump错误 在编写C++程序中,我们经常会遇到一种错误,segment fault, 这种coredump错误 会导致程序运行时异常退出或者终止,这种错误没有明显错 ...

  4. 通讯录管理系统(C++)

    前言 本程序采用VS2019开发实现 博主尽可能完善并健壮了程序功能,如有不理想之处,请加以指正,博主会在第一时间修改完善.原创不易,望"推荐","关注",&q ...

  5. php异步:在php中使用fsockopen curl实现类似异步处理的功能方法

    PHP从主流来看,是一门面向过程的语言,它的最大缺点就是无法实现多线程管理,其程序的执行都是从头到尾,按照逻辑一路执行下来,不可能出现分支,这一点是限制php在主流程序语言中往更高级的语言发展的原因之 ...

  6. flask框架安装使用

    开篇 个人工作中需要用到flask,所以特地搭建了用一下,熟悉操作 一.centos云服务器环境下 falsk作为一个python的轻量级的web框架,基本上相当于一个内核,各种功能都需要扩展第三方来 ...

  7. 攻防世界 MOBILE RemeberOther

    解题思路: 下载后解压可以得到一个apk文件和word文件.查看word文件,里面写了比较简单的一句话,未获有有效信息.(后续会讲到这个word文档的使用) word内容 运行apk文件,如图: ap ...

  8. (一)scrapy 安装及新建爬虫项目并运行

    > 参考:https://www.cnblogs.com/hy123456/p/9847570.html 在 pycharm 中并没有创建 scrapy 工程的选项,需要手动创建. 这里就有两种 ...

  9. linux mailx 发送邮件到qq邮箱

    POP3/SMTP服务默认是开启的,没开启的点开启 然后点击生成授权码,发送消息,就会给出授权码了 yum install mailx # centos sudo apt-get install he ...

  10. Typora笔记上传到博客

    Typora笔记上传到博客 Markdown是一种轻量级标记语言,排版语法简洁,让人们更多地关注内容本身而非排版.它使用易读易写的纯文本格式编写文档,可与HTML混编,可导出 HTML.PDF 以及本 ...