A Heads or Tails
题意:
给出x , y , a ,b , 求{p , q} , a <= p <= x ,b <= q <= y , p > q.
解法:
无
Code:
int x , y , a , b;
vector<PII> ans;
void solve(){
ans.clear();
for(int i = a ; i <=x ; ++i)
for (int j = b ; j <= y ; ++j)
if (i > j){
ans.PB( MP(i , j));
}
printf("%d\n" , ans.size());
for (int i = 0 ; i < ans.size() ; ++i)
printf("%d %d\n" , ans[i].first , ans[i].second);
}
int main(){
while(cin >> x >>y >> a >> b){
solve();
}
}
B Big Segment
题意:
给出n 对数字[l , r], 问是否有其中一组可以覆盖所有线段
解法:
取lmin , rmax, 然后查找
Code:
int a , b , n;
vector< PII > seg;
void solve(){
seg.clear();
int c , d;
for (int i = 0 ; i < n ; ++i){
cin >> a >> b;
if (i == 0) c = a , d = b;
else checkMax(d , b) , checkMin(c , a);
seg.PB( MP(a , b) );
}
for (int i = 0 ; i < n ; ++i){
if (seg[i].first == c && seg[i].second == d){
printf("%d\n" , i + 1);
return ;
}
}
cout << "-1" << endl;
}
int main(){
while (cin >> n) solve();
}
C King's Path
题意:
从(x0 , y0) 点到 (x1 , y1) 点,只允许走几条线段,八个方向。问最少需要多少步。
重要条件——点数最多1e5.。。曹操曹操。。。。
解法:
裸bfs。Set判断点是否存在,map记录距离。
Code:
const int N = 2e5;
set< PII > vis;
map< PII , int > step;
queue < PII > q;
const int dir[][2] = { {-1 , -1} , { -1 , 0 } , {-1 , 1} , {0 , -1} , {0 , 1} , {1 , -1} , {1 , 0} , {1 , 1} };
PII st , ed;
int n , a , b , r;
void solve(){
vis.clear();
step.clear();
while (!q.empty()) q.pop();
step[st] = 0;
cin >> n ;
vis.insert(st);
vis.insert(ed);
while(n--){
cin >> r >> a >> b;
for (int i = a ; i <= b ; ++i)
vis.insert( MP(r , i) );
}
q.push(st);
while (!q.empty()){
PII go , now = q.front();
int nowstep = step[now];
q.pop();
for (int d = 0 ; d < 8 ; ++d){
go = MP(now.first + dir[d][0] , now.second + dir[d][1]);
if (vis.find(go) != vis.end() && step.find(go) == step.end()){
step[go] = nowstep + 1;
q.push(go);
if (go == ed){
cout << nowstep + 1 << endl;
return;
}
}
}
}
cout << -1 << endl;
0}
int main(){
while(cin >> st.first >> st.second >> ed.first >> ed.second) solve();
}
D Dispute
题意:
给一张无向图,如果press一个点的话,它与直接相邻的点的计数器都+1。给一个序列a要使得所有的计数器数字都不为a[i] ,每个点只可以press一次,问构造方法。
解法:
直接构造,如果当前计数器的值=a[i] 的话press这个点。因为每次加值,所以a[i]= c[i] 只可能出现一次,于是一定有解。
Code:
const int N = 100009;
VI adj[N];
int a[N], c[N]; VI res;
int n, m;
#define v adj[u][i]
void press(int u){
++c[u]; res.PB(u); REP(i, SZ(adj[u]))
if (a[v] == ++c[v]) press(v);
}
#undef v
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
RD(n, m); DO(m){
int u, v; RD(u, v);
adj[u].PB(v); adj[v].PB(u);
}
REP_1(i, n) RD(a[i]);
REP_1(i, n) if (a[i] == c[i])
press(i);
cout << SZ(res) << endl;
REP(i, SZ(res)) OT(res[i]);
}
0
E XOR on Segment
题意:
一个1e5个元素的序列,5e4个操作:
1、 将某个区间亦或一个值
2、 求某个区间的和
解法:
简单线段树。将每个数字拆成二进制,开20棵线段树,每棵线段树记录数列的每一个二进制位的01.对于操作1,将亦或的数字拆开,如果当前位是1那么将区间01翻转,否则不管;对于操作2,枚举0~20 ,求区间1的个数,乘以1 << i 求和即可。要注意的是输出答案是long long。
Code:
#define MAXN 100001
int n,m;
int a[MAXN] , ia[MAXN];
const int N = 21;
struct Seg{
struct SEGTREE{
int l,r,num,op;
}tree[MAXN*4];
void refresh(int root){
tree[root].num = tree[root<<1].num + tree[root<<1|1].num;
}
void buildsegtree(int root,int l,int r)
{
tree[root].l = l; tree[root].r = r;
tree[root].op = -1;
if(l == r)
{
tree[root].num = a[l];
return ;
}
int mid = (l+r)>>1;
buildsegtree(root<<1,l,mid);
buildsegtree(root<<1|1,mid+1,r);
refresh(root);
}
void pushdown(int root)
{
if(tree[root].op == -1) return ;
if(tree[root].l != tree[root].r)
{
if(tree[root].op == 2)
{
switch(tree[root<<1].op)
{
case -1: tree[root<<1].op = 2; break;
case 0: tree[root<<1].op = 1; break;
case 1: tree[root<<1].op = 0; break;
case 2: tree[root<<1].op = -1; break;
}
switch(tree[root<<1|1].op)
{
case -1: tree[root<<1|1].op = 2; break;
case 0: tree[root<<1|1].op = 1; break;
case 1: tree[root<<1|1].op = 0; break;
case 2: tree[root<<1|1].op = -1; break;
}
}
else
tree[root<<1].op = tree[root<<1|1].op = tree[root].op;
}
if(tree[root].op == 0)
{
tree[root].num
= 0;
}
else if(tree[root].op == 1)
{
tree[root].num
= tree[root].r - tree[root].l + 1;
}
else
{
tree[root].num = tree[root].r - tree[root].l + 1 - tree[root].num;
}
tree[root].op = -1;
}
int query_num(int root,int l,int r)
{
pushdown(root);
if(tree[root].l == l && tree[root].r == r)
return tree[root].num;
int mid = (tree[root].l + tree[root].r)>>1;
if(r <= mid)
return query_num(root<<1,l,r);
else if(l > mid)
return query_num(root<<1|1,l,r);
else
return query_num(root<<1,l,mid) + query_num(root<<1|1,mid+1,r);
}
void update(int root,int l,int r,int op)
{
pushdown(root);
if(tree[root].l == l && tree[root].r == r)
{
tree[root].op = op;
return ;
}
int mid = (tree[root].l + tree[root].r)>>1;
if(r<=mid)
update(root<<1,l,r,op);
else if(l > mid)
update(root<<1|1,l,r,op);
else
{
update(root<<1,l,mid,op);
update(root<<1|1,mid+1,r,op);
}
pushdown(root<<1);
pushdown(root<<1|1);
refresh(root);
}
}Meng[N];
int MM[N];
void init(){
for (int i = 0 ; i < N ; ++i)
MM[i] = 1 << i;
}
int main()
{
init();
while(cin >> n)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&ia[i]);
}
for (int i = 0 ; i < N ; ++i){
int j = (1 << i);
for (int k = 1 ; k <= n ; ++k){
if (ia[k] & j) a[k] = 1;
else a[k] = 0;
}
Meng[i].buildsegtree(1 , 1 , n);
}
int op,a,b,c;
cin >> m ;
while(m--)
{
scanf("%d" , &op);
if (op == 1){
scanf("%d%d" , &a , &b);
long long ans = 0;
for (int i = 0 ; i < N ; ++i){
long long res = MM[i];
long long ret = Meng[i].query_num(1,a,b);
res *= ret;
ans += res;
}
cout << ans << endl;
}
else{
scanf("%d%d%d" , &a , &b , &c);
for (int i = 0 ; i < N; ++i){
if (c & MM[i]) Meng[i].update(1 , a , b , 2);
}
}
}
}
return 0;
}
总结:
1、 岛岛的英文太神了啊!!!-- 尼玛瞬间题目就读完了Orz
2、 对木板的信心太渣了啊,E的木板用的太不熟悉
3、 题意太隐晦本屌丝的狗眼瞎了啊。。。C的点数小于1e5完全没看见,跪。
4、 下次Div2 一定要AK= =