2018-2019 ACM—ICPC SEERC 题解

2018 - 2019 SEERC 题解

比赛发出来太新了,网上根本就搜不到题解,补题补的太难受了.
在这里分享一篇我自己写的题解,也方便别人补题.

题目链接

http://codeforces.com/gym/101964/attachments/download/7814/seerc-2018.pdf


A.Numbers

不留坑,这题不会.


B.Broken Watch

题解

先考虑三个针长度各不一样的情况.

注意到需要对nnn分奇偶性进行讨论.

  1. nnn为偶数的时候,固定111号针的位置,枚举222号针的位置,那么333号针的位置必然在1,21,21,2号针的反向延长线形成的扇形区域内(可与边界重合).
    并注意到当1,21,21,2号针反向的时候,333号针有n−2n-2n2种取法.
    可以得到公式n(1+2+...+n2+n−2)n(1+2+...+\frac{n}{2} + n-2)n(1+2+...+2n+n2).
  2. nnn为奇数的时候,固定111号针的位置枚举222号针的位置,那么333号针的位置必然在1,21,21,2号针反向延长线之间(不能与边界重合).
    可以得到公式n(1+2+...+⌊n2⌋)n(1+2+...+\lfloor \frac{n}{2} \rfloor)n(1+2+...+2n)

而当三根针有两根相同时,需要对答案除以2!2!2!,当三根全都相同时,需要对答案除以3!3!3!,这题就结束了.不明白为什么这个题比CCC题过得人少?

代码

org = input().split(" ")a = int(org[0])
b = int(org[1])
c = int(org[2])
n = int(org[3])len = 1if a == b and b == c:len = 6
elif a == b or b == c or a == c:len = 2mod = 2**64ans = 0
if n % 2 == 0:ans = (n*((n//2-1)*(n//2+2)+(n-2))//len )% mod
else:ans = (n*(n//2)*(n//2+1)//len) % modprint(ans)

C.Tree

题解

训练的时候想了一种树dp的做法,不太好调,幸好最后还是A掉了.赛后翻比别人代码发现还有一种很巧妙地方法,即枚举树的直径.两种方法我都简略说一下.

方法一.树dp

二分最大距离MMM,然后树dpdpdpcheckcheckcheck可行性.

定义dp[i][j]dp[i][j]dp[i][j]表示以iii为根的子树,选出来的黑点中距iii节点距离不会超过jjj,所能选出最多的黑点个数.
并记lim=MIN{M−1−j,j−1}lim = MIN\{M-1-j,j-1\}lim=MIN{M1j,j1}
那么转移就是:
假设v1,v2,...,vmv_1,v_2,...,v_mv1,v2,...,vmiii的儿子节点.

  1. MIN1≤p≤m{dp[vp][j−1]+∑q!=pdp[vq][lim]}→dp[i][j]MIN_{1\le p \le m}\{dp[v_p][j-1] + \sum_{q != p}dp[v_q][lim]\} \rightarrow dp[i][j]MIN1pm{dp[vp][j1]+q!=pdp[vq][lim]}dp[i][j]

  2. dp[i][j−1]→dp[i][j]dp[i][j-1] \rightarrow dp[i][j]dp[i][j1]dp[i][j]

最后只要看dp[1][M]≥kdp[1][M] \ge kdp[1][M]k.

时间复杂度?
O(n3log(n))O(n^3log(n))O(n3log(n))

方法二.枚举树的直径

先预处理出树上两点之间的距离(使用Floyd算法即可).

注意到将黑点取出之后会形成一颗虚树,并且两两之间最长的距离就是

然后我们考虑枚举这颗虚树的直径,假设是(i,j)(i,j)(i,j),然后再枚举黑点,黑点进到虚树中一定不能使直径边长.所以就要要求dis[i][k]≤dis[i][j]&&dis[k][j]≤dis[i][j]dis[i][k] \le dis[i][j] \&\& dis[k][j] \le dis[i][j]dis[i][k]dis[i][j]&&dis[k][j]dis[i][j].

时间复杂度O(n3)O(n^3)O(n3)

这个方法简单多了.

注意:不需要建虚树,说虚树主要是好描述.

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)using namespace std;const int maxn = 105;
int n,m,val[maxn],dp[maxn][maxn];
vector<int> G[maxn];void dfs(int cur,int pre,int mid){for(int nx : G[cur]) if(nx != pre) dfs(nx,cur,mid);if(val[cur] == 1) dp[cur][0] = 1;for(int i = 1;i <= mid;i++){int limit = min(mid-1-i,i-1), sum = 0;if(limit >= 0) for(int nx : G[cur]) if(nx != pre){sum += dp[nx][limit];}dp[cur][i] = max(dp[cur][i],dp[cur][i-1]);for(int nx : G[cur]){if(nx == pre) continue;int tmp = dp[nx][i-1];if(limit >= 0) tmp += sum - dp[nx][limit];dp[cur][i] = max(dp[cur][i], val[cur]+tmp);}}
}
bool check(int mid){memset(dp,0,sizeof(dp));dfs(1,-1,mid);int f = 0;for(int i = 1;i <= n;++i)f |= dp[i][mid] >= m;return f;
}int main(){ios::sync_with_stdio(false);cin>>n>>m;for(int i = 1;i <= n;i++) cin>>val[i];for(int i = 0;i < n-1;i++){int u,v;cin>>u>>v;G[u].push_back(v);G[v].push_back(u);}int l = 0, r = n;while(r - l > 1){int mid = (l + r) >> 1;if(check(mid)) r = mid;else l = mid + 1;}if(check(l)) cout<<l<<endl;else cout<<r<<endl;return 0;
}

D.Space Station

题解

一道很神奇的题,需要先猜出结论,然后再进行树上背包.思路弄清楚了实现起来很简单.

简述一下题意:一颗nnn个结点的带权树,要求从111号点出发,遍历所有的,然后回到111号点.途中可以最多使用mmm次技能,技能花费时间为kkk,功能是在任意两点中穿越.求最小代价.

我们先来发现一些规律性的东西.

  1. 注意到一颗子树如果子树中包含的技能出发点和技能到达点共ppp个,如果ppp是偶数的时候,那么这颗子树根节点的父亲边一定要走两次(可以画图帮助理解一下)
  2. 而如果ppp是奇数的话,那么子树根节点的父亲边只需要走一次就好了.(画图帮助理解)

这就很简单了.

定义dp[i][j]dp[i][j]dp[i][j]表示以iii为根的子树,其子树中奇点个数为jjj,从iii点出发遍历完iii的子树再回到iii点,所需要的最小代价.

那么转移方程就是

∑p1+p2+...+pm=j(dp[vi][pi]+(![pi&amp;1]+1)∗ci)→dp[u][j]\sum_{p_1+p_2+...+p_m=j}(dp[v_i][p_i]+(![p_i\&amp;1]+1)*c_i) \rightarrow dp[u][j]p1+p2+...+pm=j(dp[vi][pi]+(![pi&1]+1)ci)dp[u][j]

∑p1+p2+...+pm=j(dp[vi][pi]+(![pi&amp;1]+1)∗ci)→dp[u][j+1]\sum_{p_1+p_2+...+p_m=j}(dp[v_i][p_i]+(![p_i\&amp;1]+1)*c_i) \rightarrow dp[u][j+1]p1+p2+...+pm=j(dp[vi][pi]+(![pi&1]+1)ci)dp[u][j+1]

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)
typedef std::pair<int,int> pii;
const int N = 1007; 
std::vector<pii> edge[N];
int dp[N][N],sz[N],tmp[N];
int n,m,k,T;
void upd(int &x,int y){if(y < x) x = y;
}
void dfs(int u,int fa) {sz[u] = 1;for(pii p : edge[u]) {int v = p.first,c = p.second;if(v == fa) continue;dfs(v,u);memset(tmp,0x3f,sizeof(tmp));for(int i = 0;i <= sz[u];++i) {for(int j = 0;j <= sz[v];++j) {if(i + j > 2*m) continue;if(j % 2 != 0) {upd(tmp[i+j],dp[u][i] + dp[v][j] + c);upd(tmp[i+j+1],dp[u][i] + dp[v][j] + c);}else {upd(tmp[i+j],dp[u][i] + dp[v][j] + 2*c);upd(tmp[i+j+1],dp[u][i] + dp[v][j] + 2*c);}}}sz[u] += sz[v];for(int i = 0;i <= sz[u];++i)dp[u][i] = tmp[i];}
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cin >> T;while(T--) {std::cin >> n >> m >> k;memset(dp,0,sizeof(dp));rep(i,1,n) edge[i].clear();rep(i,1,n-1) {int u,v,c;std::cin >> u >> v >> c;edge[u].push_back((pii){v,c});edge[v].push_back((pii){u,c});}dfs(1,0);int ans = 0x3f3f3f3f;for(int i = 0;i <= std::min(2*m,n);i += 2) upd(ans,dp[1][i]+(i/2*k));std::cout << ans << std::endl;}return 0;
}

E.Fisherman

题解

首先我们将钓鱼的人按照xxx坐标排个序,同时也记录一下他在答案里的顺序以便逆映射回去。
然后考虑每一条鱼能被哪些渔夫钓到,也就是考虑贡献。我们能够很简单地知道,一条鱼能够被钓到的地方在xxx轴上是一段连续的区间。当鱼的y坐标大于所给的线的长度时钓不到,否则记鱼线长度大于yyy坐标的长度l−y=dll - y = dlly=dl,能够钓到鱼区间即为[x−dl,x+dl][x-dl, x+dl][xdl,x+dl]。于是lower_bound和upper _bound找一下渔夫里面所对应的区间,然后区间加单点查询。区间加单点查询这个操作在代码里是使用了差分数组来维护的,最后算完之后把差分数组还原即可得到答案。


F.Min Max Convert

题解

大致的题意是给你两个长为nnn的数列A,BA,BA,B,然后你每次可以选择一段区间将区间覆盖成它的最大值或者是覆盖成它的最小值.要求输出一个长不超过2n2n2n的方案,将AAA数列变成BBB数列.

很明显的构造题.

我们首先要找一下规律以发现一些结论.

  1. 一个区间最多通过两次操作可以将区间覆盖为区间中任意一个数.
    vvv在区间边界上时,例如v=a[l]v = a[l]v=a[l],将[l,r][l,r][l,r]覆盖为vvv的方法是:判断a[l]a[l]a[l]a[l+1]a[l+1]a[l+1]的大小关系,如果a[l]&gt;a[l+1]a[l] &gt; a[l+1]a[l]>a[l+1],那么就将[l+1,r][l+1,r][l+1,r]取最小值,再将[l,r][l,r][l,r]取最大值.
    vvv[l,r][l,r][l,r]中间时,可以将区间分成两段,分别操作.

  2. 对于BBB数列的每个数,在AAA数列中都应该有一个数与它对应.并且这些对应关系不交叉.
    比如:
    A:5,3,1,2,2,4,7,6,8,6A:5,3,1,2,2,4,7,6,8,6A:5,3,1,2,2,4,7,6,8,6
    B:1,1,2,4,4,7,7,8,8,8B:1,1,2,4,4,7,7,8,8,8B:1,1,2,4,4,7,7,8,8,8
    那么对应关系是这样的:

在这里插入图片描述
好难讲,直接看我代码吧.

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)const int N = 100007;
int A[N],B[N],Loc[N];
char C[N<<1];int L[N<<1],R[N<<1];
int tot;
struct E{int b,e,x;
}es[N];
int etot = 0;
int n;
void Do(char c,int l,int r) {C[tot] = c;L[tot] = l;R[tot] = r;++tot;
}
int main() {scanf("%d",&n);rep(i,1,n) scanf("%d",&A[i]);rep(i,1,n) scanf("%d",&B[i]);int pos = 1;rep(i,1,n) {while(pos <= n && A[pos] != B[i]) pos ++;if(pos == n+1) return 0*puts("-1");Loc[i] = pos;	}int p = 1;rep(i,1,n) {if(Loc[i] != Loc[i+1]) {es[etot++] = (E){p,i,Loc[i]};p = i+1;}}for(int i = etot-1;i >= 0;--i) {if(es[i].x < es[i].b) {if(A[es[i].x] >= A[es[i].x+1]) {Do('m',es[i].x+1,es[i].e);Do('M',es[i].x,es[i].e);}if(A[es[i].x] < A[es[i].x+1]) {Do('M',es[i].x+1,es[i].e);Do('m',es[i].x,es[i].e);}}}rep(i,0,etot-1) {if(es[i].x > es[i].e) {if(A[es[i].x] <= A[es[i].x-1]) {Do('M',es[i].b,es[i].x-1);Do('m',es[i].b,es[i].x);}	if(A[es[i].x] > A[es[i].x-1]) {Do('m',es[i].b,es[i].x-1);Do('M',es[i].b,es[i].x);}}}rep(i,0,etot-1) {if(es[i].b <= es[i].x && es[i].x <= es[i].e) {if(es[i].x > es[i].b && A[es[i].x] >= A[es[i].x-1]) {Do('m',es[i].b,es[i].x-1);Do('M',es[i].b,es[i].x);}if(es[i].x > es[i].b && A[es[i].x] < A[es[i].x-1]) {Do('M',es[i].b,es[i].x-1);Do('m',es[i].b,es[i].x);}if(es[i].x < es[i].e && A[es[i].x] >= A[es[i].x+1]) {Do('m',es[i].x+1,es[i].e);Do('M',es[i].x,es[i].e);}if(es[i].x < es[i].e && A[es[i].x] < A[es[i].x+1]) {Do('M',es[i].x+1,es[i].e);Do('m',es[i].x,es[i].e);}}}std::cout << tot << std::endl;rep(i,0,tot-1) {printf("%c %d %d\n",C[i],L[i],R[i]);}return 0;
}

G.Matrix Queries

题解

队友LNCLNCLNC写的.

结论:我们称依题目给出的公式计算矩阵AAA的得分时递归处理到的矩阵均称为AAA的“子矩阵”,记这些矩阵中有nnn个为不“纯色”的矩阵,则矩阵A的得分为4n+14n+14n+1

证明:
用数学归纳法:当AAA1×11\times11×1的矩阵时显然结论成立。
假设A为2k×2k2^k\times2^k2k×2k的矩阵时结论成立,现证A为2k+1×2k+12^{k+1}\times2^{k+1}2k+1×2k+1矩阵时结论仍成立:

  1. AAA纯色,则其得分为1,结论成立;
  2. AAA不纯色,记其四个子矩阵的不纯色的子矩阵个数分别为n1n_1n1n2n_2n2n3n_3n3n4n_4n4,则由假设它们的得分分别为4n1+14n_1+14n1+14n2+14n_2+14n2+14n3+14n_3+14n3+14n4+14n_4+14n4+1,A中不纯色的子矩阵个数为n1+n2+n3+n4+1n_1+n_2+n_3+n_4+1n1+n2+n3+n4+1,由定义A的得分s=5+(n1+n2+n3+n4)=4(n1+n2+n3+n4+1)+1s=5 +(n_1+n_2+n_3+n_4)=4(n_1+n_2+n_3+n_4+1)+1s=5+(n1+n2+n3+n4)=4(n1+n2+n3+n4+1)+1,结论成立。

综上结论得证。

考虑到一个矩阵为纯色则这个矩阵的每行需修改相同奇偶次且每列也需修改相同奇偶次,统计有多少合法位置的连续2k2^k2k行与列修改的奇偶次数相同,相乘结果即2k×2k2^k\times2^k2k×2k大小矩阵中纯色的个数,求反面即可。这些区间形成了线段树的结构,用线段树维护即可。

代码

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
const int maxn = (1<<20)+10;
ll seg[2][maxn*4],ans[2][21];void modify(int id,int o,int l,int r,int deep,int x){if(l == r){seg[id][o] ^= 1;return;}int mid = (l + r) >> 1;if(x <= mid) modify(id,o<<1,l,mid,deep+1,x);else modify(id,o<<1|1,mid+1,r,deep+1,x);if(seg[id][o] != -1) ans[id][deep]--;if(seg[id][o<<1] == seg[id][o<<1|1]) seg[id][o] = seg[id][o<<1];else seg[id][o] = -1;if(seg[id][o] != -1) ans[id][deep]++;
}
inline void read(int& x){char ch = getchar();x = 0;for(;ch < '0' || ch > '9';ch = getchar());for(;ch >= '0' && ch <= '9';ch = getchar()) x = x*10+(ch-'0');
}
inline void write(ll x){char ch = x%10+'0';if(x >= 10) write(x/10);putchar(ch);
}int main(){ios::sync_with_stdio(false);int n,m,sz;ll sum = 0;read(sz);read(m);n = (1 << sz);for(int i = 0;i < sz;i++){ans[0][i+1] = ans[1][i+1] = (1 << i);sum += (1ll << (i * 2)); }for(int i = 0;i < m;i++){int id, x;read(id);read(x);modify(id,1,1,n,1,x);ll tmp = 0;for(int i = 1;i <= sz;i++){tmp += 1ll*ans[0][i] * ans[1][i];}write(4ll * (sum - tmp) + 1);puts("");}return 0;
}

H.Modern Djinn

题解

留坑.


I.Inversion

题解

第一步,根据图恢原来的排列.

在得到原来的排列以后,我们从排列中挑选一些位置(p1,p2,...pm)(p_1,p_2,...p_m)(p1,p2,...pm)组成一个独立支配集.必然有a[p1]&lt;a[p2]&lt;...&lt;a[pm]a[p_1] &lt; a[p_2] &lt;... &lt; a[p_m]a[p1]<a[p2]<...<a[pm],只有这样,集合里的点之间才没有边相连,并且还要满足条件即[pi,pi+1][p_i,p_{i+1}][pi,pi+1]之间的数要么大于a[pi+1]a[p_{i+1}]a[pi+1],要么小于a[i]a[i]a[i].

并且在排列中不可能存在p0&lt;p1并且a[p0]&lt;a[p1]p_0 &lt; p_1并且a[p_0] &lt; a[p_1 ]p0<p1a[p0]<a[p1],否则的话,它也应该存在于集合当中,应为它与集合中的所有点都无边相连.同理,不存在pm+1&gt;pmp_{m+1} &gt; p_mpm+1>pm,使得a[pm+1]&gt;a[pm]a[p_{m+1}] &gt; a[p_m]a[pm+1]>a[pm].

如果p&lt;q且a[p]&lt;a[q]且a[p,q]p&lt;q且a[p] &lt; a[q]且a[p,q]p<qa[p]<a[q]a[p,q]之间的数不会存在介于a[p]a[p]a[p]a[q]a[q]a[q]之间的数,就从pppqqq连边.

答案就是从入度为000的点,跑到出度为000的点的路径数之和.

拓扑序dp一下结束.

代码

#include <bits/stdc++.h>
using namespace std;typedef long long ll;
const int maxn = 105;
int a[maxn], in[maxn], cnt, x[maxn],n,m;
ll dp[maxn];
bool vis[maxn][maxn];
vector<int> G[maxn];ll dfs(int cur){if(dp[cur] != -1) return dp[cur];dp[cur] = 0;if(G[cur].size() == 0) dp[cur]++;for(int nx : G[cur]){dp[cur] += dfs(nx);}return dp[cur];
}int main(){ios::sync_with_stdio(false);cin>>n>>m;for(int i = 0;i < m;i++){int u,v;cin>>u>>v;vis[u][v] = vis[v][u] = 1;if(u < v) swap(u,v);G[u].push_back(v);in[v]++;}for(int i = 1;i <= n;i++){for(int j = i+1;j <= n;j++){if(vis[i][j]) continue;G[i].push_back(j);in[j]++;}}queue<int> q;for(int i = 1;i <= n;i++){if(in[i] == 0) q.push(i);}while(!q.empty()){int cur = q.front();q.pop();a[cur] = ++cnt;for(int nx : G[cur]){in[nx]--;if(in[nx] == 0) q.push(nx);}}memset(in,0,sizeof(in));for(int i = 1;i <= n;i++) G[i].clear();for(int i = 1;i <= n;i++){for(int j = i+1;j <= n;j++){if(a[i] > a[j]) continue;bool flag = true;for(int k = i + 1;k < j;k++)if(a[k] > a[i] && a[k] < a[j]) flag = false;if(flag){G[i].push_back(j);in[j]++;}}}ll ans = 0;memset(dp,-1,sizeof(dp));for(int i = 1;i <= n;i++) if(in[i] == 0) ans += dfs(i);cout<<ans<<endl;return 0;
}

J.Rabbit vs Turtle

题解

留坑


K.Points and Rectangles

题解

cdqcdqcdq分治的一道比较裸的题.

像这种能用二维线段树做的题(空间爆炸)都可以转换成离线cdq分治去解决.

每个点算作111eventeventevent.

每个矩形按照左边和右边拆成两个eventeventevent,每个eventeventevent包含上下边界.

我们考虑单独对点和矩形算贡献.

  1. 对矩形算贡献:
    所有在该矩形前加的点都对矩形的左边eventeventevent111个负的影响,对矩形的右边eventeventevent111个正的贡献.
    维护一个树状数组,iii位置的值代表目前存在的点yyy值为iii的有多少个.
    那么对于每一个分治过程按照eventeventeventxxx从小到大的过程扫过来,遇见矩形左边eventeventevent就将贡献减去sum[down,up]sum[down,up]sum[down,up],遇见矩形右边eventeventevent,就将贡献加上sum[down,up]sum[down,up]sum[down,up].
    需要注意的一点是当多个eventeventeventxxx相同的情况下,我们按照矩形左边eventeventevent,点eventeventevent,矩形右边eventeventevent 顺序扫.

  2. 对点算贡献.
    矩形的左边eventeventevent对点会产生正的贡献,而矩形的右边eventeventevent会对点产生负的贡献.
    还是按照eventeventeventxxx值从小到大的过程扫过来,遇见矩形左边eventeventevent就将新树状数组的downdowndown位置+1+1+1,将up+1up+1up+1位置−1-11.
    遇见矩形右边eventeventevent就将新树状数组的downdowndown位置−1-11,将up+1up+1up+1位置+1+1+1.
    在遇见点eventeventevent时候,直接统计sum[0,y]sum[0,y]sum[0,y]的值就是包含这个点的矩形的贡献.
    需要注意的一点是当多个eventeventeventxxx相同的情况下,我们按照矩形左边eventeventevent,点eventeventevent,矩形右边eventeventevent 顺序扫.

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define pr(x) std::cout << #x << ':' << x << std::endl
#define rep(i,a,b) for(int i = a;i <= b;++i)
#define int long long
int op[3] = {2,1,3};
const int N = 1e6;
struct event{int tp,id,x,up,down;event(int tp=0,int id=0,int x=0,int up=0,int down=0):tp(tp),id(id),x(x),up(up),down(down){}friend bool operator<(event &e1,event &e2) {return e1.x == e2.x ? (op[e1.tp] < op[e2.tp]) : (e1.x < e2.x);}
}es[N<<1];
int tot;int a[N],ans[N];
int bit1[N],bit2[N];
int ec = 0,q;event tmp[N<<1];int lowbit(int x) {return x & (-x);
}void add(int bit[],int pos,int x) {for(;pos < N;pos += lowbit(pos))bit[pos] += x;
}int sum(int bit[],int pos) {int res = 0;for(;pos;pos -= lowbit(pos)) {res += bit[pos];}return res;
}void clr(int bit[],int pos) {if(pos <= 0) return ;for(;pos < N;pos += lowbit(pos))bit[pos] = 0;
}void solve(int l,int r) {if(l == r) return ;int mid = (l + r) >> 1;solve(l,mid);solve(mid+1,r);std::vector<int> vec1,vec2;int s = 0,p = l,q = mid+1;while(p <= mid && q <= r) {if(es[p] < es[q]) {if(es[p].tp == 0) {add(bit1,es[p].up,1);vec1.push_back(es[p].up);}else if(es[p].tp == 1) {add(bit2,es[p].down,1);add(bit2,es[p].up+1,-1);vec2.push_back(es[p].down);vec2.push_back(es[p].up+1);}else if(es[p].tp == 2) {add(bit2,es[p].down,-1);add(bit2,es[p].up+1,1);vec2.push_back(es[p].down);vec2.push_back(es[p].up+1);}tmp[s++] = es[p++];}else {if(es[q].tp == 0) {ans[es[q].id] += sum(bit2,es[q].up);}else if(es[q].tp == 1) {ans[es[q].id] -= sum(bit1,es[q].up) - sum(bit1,es[q].down-1);}else if(es[q].tp == 2) {ans[es[q].id] += sum(bit1,es[q].up) - sum(bit1,es[q].down-1);}tmp[s++] = es[q++];}}while(p <= mid) tmp[s++] = es[p++];while(q <= r){if(es[q].tp == 0) {ans[es[q].id] += sum(bit2,es[q].up);}else if(es[q].tp == 1) {ans[es[q].id] -= sum(bit1,es[q].up) - sum(bit1,es[q].down-1);}else if(es[q].tp == 2)ans[es[q].id] += sum(bit1,es[q].up) - sum(bit1,es[q].down-1);tmp[s++] = es[q++];}for(int x : vec1) clr(bit1,x);for(int x : vec2) clr(bit2,x);rep(i,l,r) {es[i] = tmp[i-l];}
}signed main() {std::ios::sync_with_stdio(false);std::cin >> q;a[ec++] = 0;rep(i,1,q) {int tp;std::cin >> tp;if(tp == 1) {int x,y;std::cin >> x >> y;x+=2,y+=2;a[ec++] = x;a[ec++] = y;es[tot++] = event(0,i,x,y,0);}	else if(tp == 2) {int _a,_b,_c,_d;std::cin >> _a >> _b >> _c >> _d;_a+=2,_b+=2,_c+=2,_d+=2;a[ec++] = _a;a[ec++] = _b;a[ec++] = _c;a[ec++] = _d;es[tot++] = event(1,i,_a,_d,_b);es[tot++] = event(2,i,_c,_d,_b);}}	std::sort(a,a+ec);ec = std::unique(a,a+ec)-a;for(int i = 0;i < tot;++i) {es[i].x = std::lower_bound(a,a+ec,es[i].x)-a;es[i].up = std::lower_bound(a,a+ec,es[i].up)-a;es[i].down = std::lower_bound(a,a+ec,es[i].down)-a;}solve(0,tot-1);rep(i,1,q) {ans[i] += ans[i-1];std::cout << ans[i] << std::endl;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/320999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【DP】过桥

过桥 题目大意&#xff1a; 有n个人要过一条桥&#xff0c;每个人都有自己的过桥时间&#xff0c;一条桥同时只能有2个人过&#xff08;过桥时间求较慢的一人&#xff09;&#xff0c;且要有人拿着手电筒才能过&#xff0c;只有一个手电筒&#xff0c;且不能扔手电筒&#xf…

.NET Core完成向RyuJIT的迁移

.NET Core CLR团队宣布&#xff0c;他们的.NET Core平台现在已经是完全基于其下一代即时编译器RyuJIT。有人可能不知道&#xff0c;在.NET Core中&#xff0c;编译器&#xff08;Roslyn&#xff09;会把C#代码编译成CIL&#xff08;公共中间语言&#xff09;字节码。接下来&…

【DP】【BFS】迷之阶梯

迷之阶梯 题目大意&#xff1a; 有n层阶梯&#xff0c;如果上面一层离这一层只有1个单位高度&#xff0c;就可以直接上去&#xff0c;也可以下去一层&#xff0c;当下去k层时&#xff0c;可以向上飞2k{2}^{k}2k个单位高度&#xff0c;当然要找到一个小于等于这个高度的阶梯落…

COMCMS_CORE 起步篇,如何运行和部署

前言&#xff1a;关于最近开源后&#xff0c;不少朋友问&#xff0c;怎么我下载下来&#xff0c;运行不了。或者怎么没有左边菜单。货不对板&#xff1f;还是我吃了数据&#xff1f;感言&#xff1a;开源不容易&#xff0c;更不容易的是&#xff0c;明明毫无保留&#xff0c;还…

UVALive7670 Asa's Chess Problem,上下界费用流,另类解法

Asa’s Chess Problem 先阐述一下带上下界的边怎么建. 带上下界的建图方法 设我要建一条边(u→v)(u\rightarrow v)(u→v),流量上界为upupup,下界为downdowndown,费用为costcostcost.则我需要建两条边. 为保证一定会有downdowndown的流量流过去,我们可以建立一条u→vu \right…

ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了

引言在使用asp.net core 进行api开发完成后&#xff0c;书写api说明文档对于程序员来说想必是件很痛苦的事情吧&#xff0c;但文档又必须写&#xff0c;而且文档的格式如果没有具体要求的话&#xff0c;最终完成的文档则完全取决于开发者的心情。或者详细点&#xff0c;或者简单…

.NET Core微服务之基于Exceptionless实现分布式日志记录

一、Exceptionless极简介绍Exceptionless 是一个开源的实时的日志收集框架&#xff0c;它可以应用在基于 ASP.NET&#xff0c;ASP.NET Core&#xff0c;Web API&#xff0c;Web Forms&#xff0c;WPF&#xff0c;Console&#xff0c;ASP.NET MVC 等技术开发的应用程序中&#x…

.netcore 整合 log4net

1.背景前两天&#xff0c;曾经的一个同事咨询我&#xff0c;怎样将log4net以中间件的形式整合到core里边去。我不假思索的回答&#xff0c;这种问题应该有人做过吧&#xff0c;他说没有。于是&#xff0c;我去博客园搜了下&#xff0c;发现还真没有&#xff0c;全部都是传统.NE…

Asp.Net Core中利用Seq组件展示结构化日志功能

在一次.Net Core小项目的开发中&#xff0c;掌握的不够深入&#xff0c;对日志记录并没有好好利用&#xff0c;以至于一出现异常问题&#xff0c;都得跑动服务器上查看&#xff0c;那时一度怀疑自己肯定没学好&#xff0c;不然这一块日志不可能需要自己扒服务器日志来查看&…

Apache SkyWalking的架构设计【译文】

Apache SkyWalking提供了一个功能强大并且很轻量级的后端。在此&#xff0c;将介绍为什么采用以下方式来设计它&#xff0c;以及它又是如何工作的。架构图对于APM而言&#xff0c;agent或SDKs仅是如何使用libs的技术细节。手动或自动的形式与架构无关&#xff0c;因此在本文中&…

通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core?

什么是.NET&#xff1f;什么是.NET Framework?本文将从上往下&#xff0c;循序渐进的介绍一系列相关.NET的概念&#xff0c;先从类型系统开始讲起&#xff0c;我将通过跨语言操作这个例子来逐渐引入一系列.NET的相关概念&#xff0c;这主要包括&#xff1a;CLS、CTS(CLI)、FCL…

.Net Core小技巧 - Hosted Services + Quartz实现定时任务调度

背景之前一直有朋友问&#xff0c;.Net Core Linux环境有没有类似Windows服务的东西。其实是有的&#xff0c;我了解的方法有两种&#xff1a;#1 创建一个ASP.Net Core的Web项目&#xff08;如Web API&#xff09;&#xff0c;然后通过添加中间件&#xff08;Middleware&#…

在.NET Core微服务中使用HostBuilder和Generic Host

基于控制台的服务中探索一个简单模式&#xff0c;以解决跨领域问题。“通用” Host和HostBuilder是随.NET Core 2.1发布而发布的新功能组件的组件。它们的一个用例是通过提供用于添加横切关注点&#xff08;例如依赖注入&#xff0c;配置和日志记录&#xff09;的模式来简化基于…

EntityFramework Core进行读写分离最佳实践方式,了解一下?

本来打算写ASP.NET Core MVC基础系列内容&#xff0c;博客评论有园友提出讲讲读写分离&#xff0c;这个问题提的好。大多数情况下&#xff0c;对于园友在评论中提出的问题&#xff0c;如果是值得深究或者大多数同行比较关注的问题我都会私下去看看&#xff0c;然后进行对应解答…

小X的加法难题

小X的加法难题 题目大意&#xff1a; 一个AB的式子&#xff0c;但之间有一些没用的空格&#xff0c;要你求出结果 原题&#xff1a; 解题思路&#xff1a; 字符输入&#xff0c;有数字就存起来&#xff0c;用加号和换行符来分开 代码&#xff1a; #include<cstdio>…

【桶排】小 X 的密码破译

小 X 的密码破译 题目大意&#xff1a; 有一堆式子&#xff0c;去重再排序后&#xff0c;按规则求出结果 原题&#xff1a; 解题思路&#xff1a; 把每一个求出来的数丢到桶里&#xff0c;然后跑一遍就可以了 代码&#xff1a; #include<cstdio> using namespace s…

Uva12325 Zombie's Treasure Chest [二分区间+模拟退火]

Zombie’s Treasure Chest 题目链接 https://cn.vjudge.net/problem/UVA-12325 题意 两种物品无穷多个,第一种物品重量s1s_1s1​,价值v1v_1v1​,第二种物品重量s2s_2s2​,价值v2v_2v2​,背包重nnn,求能装的最大价值之和. 数据全都是2e92e92e9.也就是两种物品的完全背包. 题…

Identity Server 4 预备知识 -- OpenID Connect 简介

我之前的文章简单的介绍了OAuth 2.0 (在这里: 要用Identity Server 4 -- OAuth 2.0 超级简介, 还不是很全.这篇文章我要介绍一下 OpenID Connect.OAuth 2.0 不是身份认证协议OAuth 2.0 不是身份认证(Authentication)协议. 为什么有人会认为OAuth 2.0具有身份认证的功能? 这是因…

Ocelot.JwtAuthorize:一个基于网关的Jwt验证包

Ocelot作为基于.net core的API网关&#xff0c;有一个功能是统一验证&#xff0c;它的作用是把没有访问权限的请求挡在API网关外面&#xff0c;而不是到达API网关事端的API时才去验证&#xff1b;之前我有一篇博文Ocelot统一权限验证&#xff0c;作过说明&#xff0c;这篇博文说…

【并查集】小 X 的液体混合

小 X 的液体混合 题目大意&#xff1a; 在一个玻璃瓶里&#xff0c;放入一些液体&#xff0c;某一对液体放在一起会有反应&#xff0c;当某个液体有反应时危险度就会乘2&#xff08;初值为1&#xff09;&#xff0c;问危险度最大是多少 原题&#xff1a; 解题思路&#xff1…