Gym 101964 题解
B:Broken Watch (别问,问就是队友写的)
代码:
import java.awt.List;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Vector; public class Main {
static int[]tmp;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
tmp = new int[5];
tmp[0] = 1; tmp[1] = 3; tmp[2] = 6;
int a, b, c, flag;
a = sc.nextInt();
b = sc.nextInt();
c = sc.nextInt();
long n = sc.nextLong();
if (n == 2) {
System.out.println("0");
}
else {
if (a != b && b != c && c != a) flag = 2;
else if (a != b || a != c || b != c) flag = 1;
else flag = 0;
BigInteger mod = BigInteger.valueOf(2).pow(64);
if ((n % 2) == 1) {
BigInteger ans = BigInteger.valueOf(tmp[flag]);
ans = ans.multiply(BigInteger.valueOf(n));
ans = ans.multiply(BigInteger.valueOf(n + 1));
ans = ans.multiply(BigInteger.valueOf(n - 1));
ans = ans.divide(BigInteger.valueOf(24));
System.out.println(ans.mod(mod));
}
else {
BigInteger ans1 = BigInteger.valueOf(n);
ans1 = ans1.multiply(BigInteger.valueOf(n - 2));
ans1 = ans1.divide(BigInteger.valueOf(2)); BigInteger ans2 = BigInteger.valueOf(n);
ans2 = ans2.multiply(BigInteger.valueOf(n - 2));
ans2 = ans2.multiply(BigInteger.valueOf(n - 4));
ans2 = ans2.divide(BigInteger.valueOf(24)); BigInteger ans = ans1.add(ans2);
ans = ans.multiply(BigInteger.valueOf(tmp[flag]));
System.out.println(ans.mod(mod));
}
}
sc.close();
}
}
C: Tree
题意:有一棵数,树上有黑点白点,现在让你从所有黑点中选m个,使得选出的点中,最长的路径长度最小。
题解:把每个边变成一个新的点, 然后已所有点为root, check一下以这个点为根的最长路径最小是多少。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = ;
vector<int> vc[N];
int vis[N];
int cnt[N];
void dfs(int o, int u, int deep){
if(vis[u]) cnt[deep]++;
for(int i = ; i < vc[u].size(); ++i){
if(vc[u][i] == o) continue;
dfs(u, vc[u][i], deep+);
}
}
int main(){
int n, m, u, v;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++i)
scanf("%d", &vis[i]);
for(int i = ; i < n; ++i){
scanf("%d%d", &u, &v);
vc[u].pb(n+i);
vc[n+i].pb(u);
vc[v].pb(n+i);
vc[n+i].pb(v);
}
int ans = inf;
for(int i = ; i < n+n; i++){
memset(cnt, , sizeof(cnt));
dfs(,i,);
//cnt[0]=0;
for(int j = ; j < n+n; j++){
if(j) cnt[j] += cnt[j-];
if(cnt[j] >= m){
ans = min(ans, j);
break;
}
}
}
printf("%d\n", ans);
return ;
}
/*
6 3
1 1 0 1 1 1
1 2
1 3
1 4
3 5
3 6 9 4
1 0 1 0 1 0 0 1 1
1 2
2 4
2 3
4 5
1 6
6 7
6 8
7 9
*/
D:Space Station
题意:一棵树,现在要求你从1号点出发,遍历完所有的边且回到1号点的花费是多少。现在你可以从任意一个点跳到另一个点跳m次,每次的花费是k,求最小花费。
题解:树形dp。
将一次跳跃拆成2次, dp[u][k] 代表的就是在已u为根的子树内跳跃k次之后他的花费是多少。
现在o 是 u的父亲, 我们要把u的信息往上传, 由分析可以得,当跳跃次数为奇数次的时候,我们只需要访问 o -> u的边一次就好了, 否则需要访问o->u的边2次,然后合并就好了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = ;
int n, m, k, T;
int head[N], to[N<<], nt[N<<], ct[N<<], tot;
inline void add(int u, int v, int w){
to[tot] = v;
ct[tot] = w;
nt[tot] = head[u];
head[u] = tot++;
}
LL dp[N][N<<], tmp[N<<];
int sz[N];
void dfs(int o, int u){
sz[u] = ;
//dp[0][u] = 0, dp[1][u] = 0;
dp[u][] = , dp[u][] = ;
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o) continue;
dfs(u, v);
memset(tmp, INF, sizeof(tmp));
//int t = min(sz[v], m*2);
for(int j = ; j <= sz[u]; ++j){
for(int k = min(sz[v], m*-j); k >= ; --k){
if(k&) tmp[j+k] = min(tmp[j+k], dp[u][j]+dp[v][k]+ct[i]);
else tmp[j+k] = min(tmp[j+k], dp[u][j]+dp[v][k]+ct[i]*);
}
}
sz[u] += sz[v];
for(int i = ; i <= sz[u]; ++i) dp[u][i] = tmp[i];
}
}
int main(){
scanf("%d", &T);
while(T--){
memset(head, -, sizeof(head));
tot = ;
scanf("%d%d%d", &n, &m, &k);
int u, v, w;
for(int i = ; i < n; ++i){
scanf("%d%d%d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
dfs(, );
LL ans = INF;
for(int i = ; i <= n; i+=){
ans = min(ans, dp[][i] + k * 1ll * (i/));
}
printf("%lld\n", ans); }
return ;
}
E:fisherman
题意:在2维平面上,有n条鱼,m个渔夫,渔夫的捕获半径为l,即所有欧几里得距离小于l的鱼都会被渔夫捕获,现在要求输出每个渔夫最多能捕获多少鱼。
题解:如果我们从渔夫的角度去圈, 我们明白渔夫是一个菱形, 要求得到菱形里面的点的个数是不好维护的。
现在我们换一种思路,将每条鱼先移动都x轴上,那么鱼还能移动的距离就是 l-y,所以鱼移动的范围就是[x-(l-y), x + (l-y)]。
然后我们把所有在这个里面的渔夫都找出来,这个过程可以用二分,然后用差分标记一下,最后得到答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 2e5 + ;
pll p[N], b[N];
int cc[N], ans[N];
int main(){
int n, m, l;
scanf("%d%d%d", &n, &m, &l);
for(int i = ; i <= n; ++i)
scanf("%d%d", &p[i].fi, &p[i].se);
for(int i = ; i <= m; ++i){
scanf("%d", &b[i].fi);
b[i].se = i;
}
sort(b+, b++m);
for(int i = ; i <= n; ++i){
int tmp = l - p[i].se;
if(tmp < ) continue;
int ll = p[i].fi - tmp;
int rr = p[i].fi + tmp;
int lll = lower_bound(b+, b++m, pll(ll, )) - b;
int rrr = upper_bound(b+, b++m, pll(rr, inf)) - b;
rrr--;
///cout << ll << " " << rr << " " << lll << " l with r " << rrr << endl;
if(lll > rrr) continue;
cc[lll]++; cc[rrr+]--;
}
for(int i = ; i <= m; ++i){
cc[i] += cc[i-];
ans[b[i].se] = cc[i];
}
for(int i = ; i <= m; ++i)
printf("%d\n", ans[i]);
return ;
}
/*
8 4 4
7 2
3 3
4 5
5 1
2 2
1 4
8 4
9 4
6 1 4 9
*/
F:Min Max Convert
题解:现在认为 to[i]就是存在 to[i]的位置能把i改造成合法点的, 并且由于路劲不能相交,所以 对于 i + 1来说 to[i+1] >= to[i],然后我们就从左边往右边找答案,然后我们可以发现2点的连线存在左偏或者右偏, 对于左偏,我们要从左到右按次序修改, 对于右偏我们则要从右到左按次序修改。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
int a[N], b[N];
vector<pll> vc[];
struct Node{
int op, l, r;
};
vector<Node> ans;
int main(){
int n;
scanf("%d", &n);
for(int i = ; i <= n; ++i) scanf("%d", &a[i]);
for(int i = ; i <= n; ++i) scanf("%d", &b[i]);
int flag = ;
for(int i = , x = ; i <= n; ++i){
while(x <= n && a[x] != b[i]) x++;
if(x > n) {
flag = ;
break;
}
if(x > i) vc[].pb({i,x});
if(x < i) vc[].pb({x,i});
}
if(flag){
int p = -, mx = -;
for(int i = ; i < vc[].size(); ++i){
int l = vc[][i].fi, r = vc[][i].se;
if(p < l) p = l, mx = a[l];
while(p < r) {
++p;
mx = max(mx, a[p]);
}
if(mx > a[r]){
ans.pb({,l,r-});
ans.pb({,l,r});
}
else ans.pb({,l,r});
mx = a[r];
}
p = n+, mx = -;
for(int i = (int(vc[].size())) - ; i >= ; --i){
int l = vc[][i].fi, r = vc[][i].se;
if(p > r) p = r, mx = a[r];
while(p > l){
--p;
mx = max(mx, a[p]);
}
if(mx > a[l]){
ans.pb({,l+,r});
ans.pb({,l,r});
}
else ans.pb({,l,r});
mx = a[l];
}
printf("%d\n", ans.size());
for(int i = ; i < ans.size(); ++i){
if(ans[i].op == ) printf("M ");
else printf("m ");
printf("%d %d\n", ans[i].l, ans[i].r);
}
}
else puts("-1");
return ;
}
G:Matrix Queries
题意:有一个2^n * 2^n的矩阵, 现在你每次都会修改一列和一行的颜色,现在问你每次修改完之后的整幅图之后的权值是多少。
题解:对于对于每一个2^k(k>1)的矩阵来说, 如果里面的颜色不是同一个颜色, 那么他就会对答案的影响就是加上4,现在只要统计多少个2^k的矩阵是不完全同样的颜色。
然后用线段树去维护关于不考虑列影响, 下对于每一个矩阵来说他的行是不是一样的。不考虑行的影响下每一个矩阵的列是不是一样的。 对于统计出一个矩阵内完全颜色相同下,那么对于这个格子来说他对应的列颜色一样,它对应的行颜色一样。我们算出个数,就可以算出不一样的个数了,然后输出答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = << ;
int cx[N], cy[N], okx[N], oky[N];
int xsz[], ysz[];
void buildx(int l, int r, int rt, int k){
okx[rt] = ;
++xsz[k];
if(l == r) return ;
int m = l+r >> ;
buildx(l,m,rt<<,k-);
buildx(m+,r,rt<<|,k-);
}
LL tot = , tot2 = ;
void buildy(int l, int r, int rt, int k){
oky[rt] = ;
++ysz[k];
tot += xsz[k]; tot2 += xsz[k];
if(l == r) return;
int m = l+r >> ;
buildy(l, m, rt<<, k-);
buildy(m+, r, rt<<|, k-);
}
void Cx(int L, int l, int r, int rt, int k){
if(l == r){
okx[rt] ^= ;
return ;
}
int m = l+r >> ;
if(L <= m) Cx(L, lson, k-);
else Cx(L,rson,k-);
if(okx[rt] != -) tot2 -= ysz[k], --xsz[k];
if(okx[rt<<] == okx[rt<<|]){
okx[rt] = okx[rt<<];
}
else okx[rt] = -;
if(okx[rt] != -) tot2 += ysz[k], ++xsz[k];
}
void Cy(int L, int l, int r, int rt, int k){
if(l == r){
oky[rt] ^= ;
return ;
}
int m = l+r >> ;
if(L <= m) Cy(L, lson, k-);
else Cy(L,rson,k-);
if(oky[rt] != -) tot2 -= xsz[k], --ysz[k];
if(oky[rt<<] == oky[rt<<|]) oky[rt] = oky[rt<<];
else oky[rt] = -;
if(oky[rt] != -) tot2 += xsz[k], ++ysz[k];
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
int l = , r = (<<n);
buildx(,r,,n);
buildy(,r,,n);
int op, h;
while(m--){
scanf("%d%d", &op, &h);
if(op) Cx(h, , r, , n);
else Cy(h, , r, , n);
printf("%lld\n",(tot-tot2)*+);
}
return ;
}
/*
2 7
1 3
0 2
1 1
1 4
0 4
0 3
1 1 */
H:Modern Djinn
题意:现在有m条单向边,如果一条单向边成立则需要 u开心 v不开心, 现在需要至少有 m/4+1 边成立, 现在要求你输出成立的方案数。
题解:将每个人的开心值 rand一下, 然后再check答案,知道满足题意,则输出。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
int a[N];
pair<int,int> p[N<<];
int id[N];
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++i)
scanf("%d%d", &p[i].fi, &p[i].se);
int k = , need = m/ + ;
do{
for(int i = ; i <= n; ++i)
a[i] = ((int)rand())&;
k = ;
for(int i = ; i <= m; ++i){
//cout << i << " "<< a[i] << endl;
if(a[p[i].fi] == && a[p[i].se] == ){
id[++k] = i;
}
} }while(k < need);
printf("%d\n", k);
for(int i = ; i <= k; ++i)
printf("%d%c", id[i], " \n"[i==k]);
}
return ;
}
I:Inversion
题解:先把图中给定的信息将原来的1-n的排列找出来,对于样例3来说,原来的序列就是[1,4,2,3],现在考虑这个序列,我们发现如果从1出发,可以往 4, 2的方向走,不可以往3走,因为2-3之间没有边,故如果序列中有3 那么一定有 2 ,我们不能直接跳过2。dp[i]代表以i结尾的方案数,现在我们要继续往后走,我们先走到后面第一个大于a[i]的值,这个点是可以被转移到的,继续往后走,走下坡路,在样例1中就是2,2也是可以通过1转移到的。 我们只要这样暴力转移就好可以得到答案了,为了方便得到最后的答案和开始dp,我们可以从给a[0] = 0, a[n+1] = n+1。故从0号点出发走到n+1号点的方案数就是答案了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = ;
int a[N], in[N];
LL dp[N];
int vis[N];
int n, m, u, v;
int Find(int x){
x++;
for(int i = ; i <= n; ++i){
if(vis[i]) continue;
x--;
if(!x) {
vis[i] = ;
return i;
}
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++i){
scanf("%d%d", &u, &v);
in[min(u,v)]++;
}
for(int i = ; i <= n; ++i)
a[i] = Find(in[i]);
a[] = , a[n+] = n+;
// for(int i = 1; i <= n; ++i)
// cout << i << ' ' << a[i] << endl;
dp[] = ;
for(int i = ; i <= n; ++i){
int x = a[i];
for(int j = i+; j <= n+; ++j){
if(a[j] > a[i]){
dp[j] += dp[i];
// cout << i << " i with j " << j << endl;
int mx = a[j];
for(int k = j+; k <= n+; ++k){
if(mx > a[k] && a[k] > a[i]){
mx = a[k];
dp[k] += dp[i];
// cout << i << " i with k " << k << endl;
}
}
break;
}
}
}
printf("%lld\n", dp[n+]);
return ;
}
/*
7 7
5 6
2 3
6 7
2 7
3 1
7 5
7 4 5 7
2 5
1 5
3 5
2 3
4 1
4 3
4 2 5 6
1 3
4 5
1 4
2 3
1 2
1 5
*/
J:Rabbit vs Turtle 我不得不说这个题目把我恶心吐了。。。。
题意:龟兔赛跑,一副 n个点m条边的图,现在要乌龟和兔子都有自己的路径,乌龟走完一条边之后他会休息一下,兔子按原来的路走。现在兔子可以作弊,兔子作弊之后乌龟不再睡觉,现在问你兔子在多少个点上作弊能赢。
限制条件: 1. 兔子在某个点作弊的时候,一定是要走从这个点出发的最短路。
2.当兔子作弊的时候,乌龟刚好要入睡,则乌龟先睡觉,再发现兔子作弊。
3.乌龟之后在不睡觉的时候才会发现兔子作弊。
4.兔子新走的路一定要比原来的路径短。
5.当兔子开始作弊的时候,下一个点一定不能是原来的路径上的下一个点。
6.当兔子和乌龟同时走到终点的时候 算兔子胜利。
7.最后的节点要按从小到大的顺序输出。
8.注意这个边是单向边
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<LL,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
const int M = 2e5 + ;
struct Node{
int u, v, t, r;
}e[M];
int head[N], to[M], ct[M], nt[M], tot = ;
void add(int u, int v, int w){
ct[tot] = w; to[tot] = v;
nt[tot] = head[u]; head[u] = tot++;
}
LL dis[N];
int n, m;
void dijkstra(){
memset(dis, INF, sizeof dis);
priority_queue<pll, vector<pll>, greater<pll> > pq;
dis[n] = ;
pq.push(pll(,n));
while(!pq.empty()){
LL x = pq.top().fi; int u = pq.top().se;
pq.pop();
if(dis[u] != x) continue;
for(int i = head[u], v; ~i; i = nt[i]){
v = to[i];
if(dis[v] > dis[u] + ct[i]){
dis[v] = dis[u] + ct[i];
pq.push(pll(dis[v],v));
}
}
}
}
LL tpre[M], tsuf[M], sum, rpre[N];
int pos[N];
LL Find(int u, int v){
LL ret = INF;
for(int i = head[u]; ~i; i = nt[i]){
if(to[i] == v) continue;
if(dis[u] == dis[to[i]]+ct[i])
ret = min(ret, ct[i]+dis[to[i]]);
}
return ret;
}
int tn, id, rn, sleep;
int ans[N], fcnt;
void boom(){
for(int i = , p = ; i < rn; ++i){
LL tmp = Find(pos[i], pos[i+]);
if(tmp >= rpre[rn] - rpre[i]) continue;
while(p <= *tn && tpre[p] < rpre[i]) p++;
if(p > * tn) continue;
LL t2;
if(p& && tpre[p] != rpre[i])
t2 = tpre[p] - rpre[i] + tsuf[(p+)/+];
else{
int q = p;
if(q&) q++;
t2 = tpre[q] - rpre[i] + tsuf[(q+)/+];
}
if(tmp <= t2)
ans[++fcnt] = pos[i];
}
}
int main(){
memset(head, -, sizeof head);
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++i){
scanf("%d%d%d%d", &e[i].u, &e[i].v, &e[i].t, &e[i].r);
add(e[i].v, e[i].u, e[i].r);
}
dijkstra();
memset(head, -, sizeof head); tot = ;
for(int i = ; i <= m; ++i) add(e[i].u, e[i].v, e[i].r);
scanf("%d", &tn);
for(int i = ; i <= tn; ++i){
scanf("%d%d", &id, &sleep);
tpre[i*-] = e[id].t;
tpre[i*] = sleep;
}
tpre[tn*] = ;
for(int i = tn; i >= ; --i)
tsuf[i] = tsuf[i+] + tpre[i*-];
for(int i = ; i <= tn*; ++i)
tpre[i] += tpre[i-];
scanf("%d", &rn);
pos[] = ;
for(int i = ; i <= rn; ++i){
scanf("%d", &id);
pos[i] = e[id].v;
rpre[i] = rpre[i-] + e[id].r;
}
boom();
printf("%d\n", fcnt);
sort(ans+, ans++fcnt);
for(int i = ; i <= fcnt; ++i)
printf("%d%c", ans[i], " \n"[i==fcnt]);
return ;
}
K:Points and Rectangles
题解:CDQ。
只要统计出每次添加一个矩形之后前面有多少个点出现在这个矩形内部,添加一个点之后在这个点在多少个矩形内就好了。
对于矩形的询问我们可以通过询问4次差分去做,对于矩形的添加,我们则可以将添加矩形的左边,然后延续长度直到矩形的右边出现,删除这个矩形。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
struct Node{
int op, x1, y1, x2, y2, id;
bool operator < (const Node & t) const{
if(x1 != t.x1) return x1 < t.x1;
return id < t.id;
}
}A[N], B[N*], C[N*];
int tot = , y[N*];
int ysz = ;
void nownode(int op, int x1, int y1, int id){
++tot; B[tot].op = op;
B[tot].x1 = x1; B[tot].y1 = y1;
B[tot].id = id;
}
LL ans[N];
LL bit[N*];
void Add(int x, int v){
while(x <= ysz ){
bit[x] += v;
x += x & (-x);
}
}
LL Query(int x){
LL ret = ;
while(x > ){
ret += bit[x];
x -= x & (-x);
}
return ret;
}
void CDQ(int l, int r){
if(l == r) return ;
int m = l+r >> ;
CDQ(l, m); CDQ(m+, r);
int k = ;
for(int i = l; i <= m; ++i)
if(B[i].id == ) C[++k] = B[i];
for(int i = m+; i <= r; ++i)
if(B[i].id) C[++k] = B[i];
if(k == || C[].id || !C[k].id) return ;
sort(C+, C++k);
for(int i = ; i <= k; ++i){
if(C[i].id == )
Add(C[i].y1, C[i].op);
else
ans[C[i].id] += C[i].op * Query(C[i].y1);
}
for(int i = ; i <= k; ++i)
if(C[i].id == )
Add(C[i].y1, -C[i].op);
}
int main(){
int n;
scanf("%d", &n);
for(int i = ; i <= n; ++i){
scanf("%d", &A[i].op);
scanf("%d%d", &A[i].x1, &A[i].y1);
y[++ysz] = A[i].y1;
if(A[i].op == ) {
scanf("%d%d", &A[i].x2, &A[i].y2);
y[++ysz] = A[i].y2;
}
}
sort(y+, y++ysz);
ysz = unique(y+, y++ysz) - y - ;
for(int i = ; i <= n; i++){
if(A[i].op == ) {
A[i].y1 = lower_bound(y+, y++ysz, A[i].y1) - y;
nownode(, A[i].x1, A[i].y1, );
}
else{
A[i].y1 = lower_bound(y+, y++ysz, A[i].y1) - y;
A[i].y2 = lower_bound(y+, y++ysz, A[i].y2) - y;
nownode(, A[i].x2, A[i].y2, i);
nownode(, A[i].x1-, A[i].y1-, i);
nownode(-, A[i].x1-, A[i].y2, i);
nownode(-, A[i].x2, A[i].y1-, i);
}
}
CDQ(, tot);
tot = ;
for(int i = ; i <= n; ++i){
if(A[i].op == ){
nownode(, A[i].x1, A[i].y1, i);
}
else {
nownode(, A[i].x1, A[i].y1, );
nownode(-, A[i].x1, A[i].y2+, );
nownode(-, A[i].x2+, A[i].y1, );
nownode(, A[i].x2+, A[i].y2+,);
}
}
CDQ(, tot);
for(int i = ; i <= n; ++i){
ans[i] += ans[i-];
printf("%lld\n", ans[i]);
}
return ;
}
Gym 101964 题解的更多相关文章
- Gym 100851 题解
A: Adjustment Office 题意:在一个n*n的矩阵,每个格子的的价值为 (x+y), 现在有操作取一行的值,或者一列的值之后输出这个和, 并且把这些格子上的值归0. 题解:模拟, 分成 ...
- Gym 101482 题解
B:Biking Duck 题意:现在有一个人要从(x1,y1)点走到(x2,y2)点, 现在走路的速度为v. 还有骑自行车的速度v2,自行车要从某个自行车站到另一个自行车站,现在我们可以视地图的边界 ...
- Gym 101470 题解
A:Banks 代码: #include<bits/stdc++.h> using namespace std; #define Fopen freopen("_in.txt&q ...
- 2016-2017 National Taiwan University World Final Team Selection Contest (Codeforces Gym) 部分题解
D 考虑每个点被删除时其他点对它的贡献,然后发现要求出距离为1~k的点对有多少个. 树分治+FFT.分治时把所有点放一起做一遍FFT,然后减去把每棵子树单独做FFT求出来的值. 复杂度$nlog^ ...
- SEERC 2018 B. Broken Watch (CDQ分治)
题目链接:http://codeforces.com/gym/101964/problem/B 题意:q 种操作,①在(x,y)处加一个点,②加一个矩阵{(x1,y1),(x2,y2)},问每次操作后 ...
- 2016百度之星 初赛2A ABEF
只做了1001 1002 1005 1006.剩下2题可能以后补? http://acm.hdu.edu.cn/search.php?field=problem&key=2016%22%B0% ...
- 2018SEERC Points and Rectangles (CDQ分治)
题:http://codeforces.com/gym/101964/problem/K 分析:https://blog.csdn.net/qq_43202683/article/details/98 ...
- Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解
题目链接:https://codeforces.com/gym/102361/problem/A 题意:给定二维平面上的\(n\)个点,\(q\)次询问,每次加入一个点,询问平面上有几个包含该点的直角 ...
- Codeforces GYM 100876 J - Buying roads 题解
Codeforces GYM 100876 J - Buying roads 题解 才不是因为有了图床来测试一下呢,哼( 题意 给你\(N\)个点,\(M\)条带权边的无向图,选出\(K\)条边,使得 ...
随机推荐
- Another option to bootup evidence files
When it comes to booting up evidence files acquired from target disk, you got two options. One is VF ...
- spark shuffle写操作之SortShuffleWriter
提出问题 1. spark shuffle的预聚合操作是如何做的,其中底层的数据结构是什么?在数据写入到内存中有预聚合,在读溢出文件合并到最终的文件时是否也有预聚合操作? 2. shuffle数据的排 ...
- android ——Toolbar
Toolbar是我看material design内容的第一个 官方文档:https://developer.android.com/reference/android/support/v7/widg ...
- CODING 告诉你如何建立一个 Scrum 团队
原文地址:https://www.atlassian.com/agile/scrum/roles 翻译君:CODING 敏杰小王子 Scrum 当中有三个角色:PO(product owner),敏捷 ...
- Markdown转载
@TOC 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown ...
- vue组件传值之$attrs、$listeners
当有父组件A,子组件B,孙子组件C的时候 A-B B-C 的传值想必大家应该都非常熟悉了,通过props和$emit和$on来进行传值 那么A-C之间的传值要怎么做呢? 1.event.bus总线传值 ...
- SAP-批量删除生产订单
1.SE38运行:PPARCHP1 2.先用COOIS导出订单,已经CLSD,没有删除的
- cs231n官方note笔记
本文记录官方note中比较新颖和有价值的观点(从反向传播开始) 一 反向传播 1 “反向传播是一个优美的局部过程.在整个计算线路图中,每个门单元都会得到一些输入并立即计算两个东西:1. 这个门的输出值 ...
- c#Winform自定义控件-目录
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...
- temperatureConversion1
(原题:https://www.python123.io/student/courses/934/groups/8102/problems/programmings/6078) Solution: # ...