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-2n−2种取法.
    可以得到公式n(1+2+...+n2+n−2)n(1+2+...+\frac{n}{2} + n-2)n(1+2+...+2n​+n−2).
  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,然后树dpdpdp来checkcheckcheck可行性.

定义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{M−1−j,j−1}
那么转移就是:
假设v1,v2,...,vmv_1,v_2,...,v_mv1​,v2​,...,vm​是iii的儿子节点.

  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]MIN1≤p≤m​{dp[vp​][j−1]+∑q!=p​dp[vq​][lim]}→dp[i][j]

  2. dp[i][j−1]→dp[i][j]dp[i][j-1] \rightarrow dp[i][j]dp[i][j−1]→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 = dll−y=dl,能够钓到鱼区间即为[x−dl,x+dl][x-dl, x+dl][x−dl,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。

证明:
用数学归纳法:当AAA为1×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_1n1​、n2n_2n2​、n3n_3n3​和n4n_4n4​,则由假设它们的得分分别为4n1+14n_1+14n1​+1、4n2+14n_2+14n2​+1、4n3+14n_3+14n3​+1和4n4+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​<p1​并且a[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<q且a[p]<a[q]且a[p,q]之间的数不会存在介于a[p]a[p]a[p]与a[q]a[q]a[q]之间的数,就从ppp向qqq连边.

答案就是从入度为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分治去解决.

每个点算作111个eventeventevent.

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

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

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

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

2018-2019 ACM—ICPC SEERC 题解相关推荐

  1. 2019 ACM - ICPC 上海网络赛 E. Counting Sequences II (指数型生成函数)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  2. 2019 ACM - ICPC 西安邀请赛 B. Product (杜教筛) 简单数论(bushi)

    G.(2019 ACM/ICPC 全国邀请赛(西安)B) Product Weblink https://nanti.jisuanke.com/t/39269 Problem && S ...

  3. 2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 The 2019 ICPC China Nanchang National Invitation ...

  4. 2019 ACM - ICPC 全国邀请赛(西安)题解(9 / 13)

    The 2019 ACM-ICPC China Shannxi Provincial Programming Contest 目录 The 2019 ACM-ICPC China Shannxi Pr ...

  5. 2018年 ACM/ICPC亚洲区域赛 青岛赛区现场赛 比赛总结

    首先祝贺自己收获了ACM生涯中的第二枚铜牌. 首先吐槽一下中石油: 周六早上来到中国石油大学,连个志愿者小姐姐都没看到.(但是看到了女装大佬).报完到之后发现教练少了一张午餐券(要不要这么粗心).为了 ...

  6. 2019 ACM/ICPC 全国邀请赛(西安)J And And And (树DP+贡献计算)

    Then n - 1n−1 lines follow. ii-th line contains two integers f_{a_i}(1 \le f_{a_i} < i)fai​​(1≤fa ...

  7. 2019 ACM/ICPC 南昌站 G,拉格朗日插值

    题意: 求∑i=1t∑k=xyf(i,k)\sum^t_{i=1}\sum^y_{k=x}f(i,k)i=1∑t​k=x∑y​f(i,k) 其中f(i,k)f(i,k)f(i,k)表示1,2,3,.. ...

  8. 2019 ACM/ICPC 南京站 E.Observation,区间筛

    题目大意 求 (∑d=LR(fdxor K))(modP)\Big(\sum\limits_{d=L}^{R} (f_d\text{ xor } K)\Big)\pmod{P}(d=L∑R​(fd​  ...

  9. 习题8-14 商队抢劫者(Caravan Robbers, ACM/ICPC SEERC 2005, UVa1616)

    原题链接:https://vjudge.net/problem/UVA-1609 分类:二分法 备注:精度问题,技巧 #include<bits/stdc++.h> using names ...

最新文章

  1. mysql多表分页查询语句_Mysql多表分页查询
  2. 如何获取mongodb中的最后N条记录?
  3. 对象属性的调用_面向对象的三主线之一:Java类及类的成员(1)
  4. 使用Picasso实现图片圆角和图片圆形
  5. The Art of Unix Programming
  6. 同时渲染两个世界:恐怖游戏《灵媒》背后的尖端技术
  7. C语言能否写windows应用程序,C语言能写windows的窗口吗?
  8. php生成图片验证码-附五种验证码
  9. django 中使用 channels 实现websocket
  10. E1 PCM设备的主要特点介绍
  11. python requests https_解决python的requests模块访问私有SSL证书产生的报错问题
  12. 【CometOJ】CometOJ#8 解题报告
  13. 最全国内外文献检索网站收集
  14. Windows HTTP服务(WinHTTP)介绍
  15. [转][学习]软件绿色联盟应用体验标准5.0_功耗标准-公示版
  16. R 回归 虚拟变量na_R语言 | 回归分析(一)
  17. windows 技巧篇-解除共享文件夹占用方法,解决共享文件被占用导致不可修改问题,查看共享文件被谁占用方法
  18. 有趣--等额本息还款
  19. 3D次时代来临 如何玩转红蓝立体游戏
  20. 在系统中自主实现全国行政区域结构化管理

热门文章

  1. c++ 模板类实现堆栈实验报告_编译原理——小型类C编译器的设计和实现(生成8086汇编代码)之1:问题定义以及总体功能...
  2. 9050 端口 linux 进程,windows和linux查看端口占用情况
  3. c语言幼儿园积木游戏,幼儿园《积木游戏》课件【三篇】
  4. bms中soh计算方式_BMS算法设计之电池SOH介绍(下)
  5. [Java基础]ListIterator
  6. [蓝桥杯2015决赛]五星填数-枚举+数论
  7. [蓝桥杯2018决赛]最大乘积-dfs
  8. java 操作日志设计_日志系统新贵 Loki,确实比笨重的ELK轻
  9. c语言火车票管理系统源代码2000行,C语言教务管理系统[2000行代码].doc
  10. 含根号的导数怎么求_数学分析Mathematical Analysis笔记整理 第四章 导数与微分