CodeForces 707D Persistent Bookcase

$dfs$,优化。

$return$操作说明该操作完成之后的状态和经过操作$k$之后的状态是一样的。因此我们可以建树,然后从根节点开始$dfs$一次(回溯的时候复原一下状态)就可以算出所有状态的答案。

对于$1$和$2$操作,可以开一个数组$a[i][j]$记录每一格子被操作$1$和$2$操作了几次。

然后开一个数组$r[i]$记录每一行被操作$3$操作了几次。 每一个真正的状态为$\left( {a\left[ i \right]\left[ j \right] + r\left[ i \right]} \right)\% 2$。 这样记录的话可以$O(1)$效率进行状态改变。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}

struct X
{
    int t,r,c,k,id;
    bool f;
}s[100010];
int sz;

int h[1010],r[1010],a[1010][1010];
int ans,n,m,k;
vector<int>G[100010];
int Ans[100010];

void work1(int op,int tag)
{
    if(tag==0)
    {
        if((a[s[op].r][s[op].c]+r[s[op].r])%2==1) return;
        s[op].f=1; a[s[op].r][s[op].c]++; h[s[op].r]++; ans++;
    }

    else
    {
        if(s[op].f==0) return ;
        a[s[op].r][s[op].c]--; h[s[op].r]--; ans--; s[op].f=0;
    }
}

void work2(int op,int tag)
{
    if(tag==0)
    {
        if((a[s[op].r][s[op].c]+r[s[op].r])%2==0) return;
        s[op].f=1; a[s[op].r][s[op].c]--; h[s[op].r]--; ans--;
    }

    else
    {
        if(s[op].f==0) return;
        a[s[op].r][s[op].c]++; h[s[op].r]++; ans++; s[op].f=0;
    }
}

void work3(int op,int tag)
{
    if(tag==0)
    {
        s[op].f=1;
        ans=ans-h[s[op].r]+(m-h[s[op].r]);
        h[s[op].r]=m-h[s[op].r];
        r[s[op].r]++;
    }

    else
    {
        ans=ans-h[s[op].r]+(m-h[s[op].r]);
        h[s[op].r]=m-h[s[op].r];
        r[s[op].r]--; s[op].f=0;
    }
}

void dfs(int x)
{
    if(s[x].t==1) work1(x,0);
    else if(s[x].t==2) work2(x,0);
    else if(s[x].t==3) work3(x,0);

    for(int i=0;i<G[x].size();i++)
        dfs(G[x][i]);
    Ans[x]=ans;
    if(s[x].t==1) work1(x,1);
    else if(s[x].t==2) work2(x,1);
    else if(s[x].t==3) work3(x,1);
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++)
    {
        scanf("%d",&s[i].t); int from=i-1;
        if(s[i].t==1) scanf("%d%d",&s[i].r,&s[i].c);
        else if(s[i].t==2) scanf("%d%d",&s[i].r,&s[i].c);
        else if(s[i].t==3) scanf("%d",&s[i].r);
        else scanf("%d",&from);
        G[from].push_back(i);
    }
    s[0].t=4; dfs(0);
    for(int i=1;i<=k;i++) printf("%d\n",Ans[i]);
    return 0;
}
时间: 2024-12-24 10:27:09

CodeForces 707D Persistent Bookcase的相关文章

【深搜】【数】Codeforces 707D Persistent Bookcase

题目链接: http://codeforces.com/problemset/problem/707/D 题目大意: 一个N*M的书架,支持4种操作 1.把(x,y)变为有书. 2.把(x,y)变为没书. 3.把x行上的所有书状态改变,有变没,没变有. 4.回到第K个操作时的状态. 求每一次操作后书架上总共多少书. 题目思路: [深搜][树] 现场有一点思路不过没敢写哈.还是太弱了. 总共只用保存一张图,把操作看成一棵树,一开始I操作连接在I-1操作后,如果遇到操作4的话,把I操作与I-1操作的

CodeForces 707D Persistent Bookcase ——(巧妙的dfs)

一个n*m的矩阵,有四种操作: 1.(i,j)处变1: 2.(i,j)处变0: 3.第i行的所有位置1,0反转: 4.回到第k次操作以后的状态: 问每次操作以后整个矩阵里面有多少个1. 其实不好处理的操作只有第四个,但是这题的思路很巧妙,123三种操作全部建立顺边,第四种操作将k和这次操作的序号建边,然后dfs进行操作即可,遇到尽头,则退回到前一个分岔点,并且回溯的过程中将操作反转. 具体见代码: 1 #include <stdio.h> 2 #include <algorithm>

CodeForces #368 div2 D Persistent Bookcase DFS

题目链接:D Persistent Bookcase 题意:有一个n*m的书架,开始是空的,现在有k种操作: 1 x y 这个位置如果没书,放书. 2 x y 这个位置如果有书,拿走. 3 x 反转这一行,即有书的位置拿走,没书的位置放上书. 4 x 返回到第x步操作之后的书架. 现在给出q个操作,询问每次操作之后书架上书的数量. 思路: 开始没有思路.后来被告知dfs. [词不达意.参考:http://blog.csdn.net/zyjhtutu/article/details/5227949

【Codeforces-707D】Persistent Bookcase DFS + 线段树

D. Persistent Bookcase Recently in school Alina has learned what are the persistent data structures: they are data structures that always preserves the previous version of itself and access to it when it is modified. After reaching home Alina decided

codeforces 707D:Persistent Bookcase

Description Recently in school Alina has learned what are the persistent data structures: they are data structures that always preserves the previous version of itself and access to it when it is modified. After reaching home Alina decided to invent

cf707D. Persistent Bookcase(离线+dfs)

题目链接:http://codeforces.com/problemset/problem/707/D  有一个n*m的书架,有K个操作,求每个操作后一共有多少本书:有4种操作: 1:x y 如果 x y 位置没有书,放一本书在上面: 2:x y如果 x y 位置有书,移走: 3:x,表示把第x行的所有又书的拿走,没书的放上去: 4:k,回到第k个操作后的状态: 离线处理k个操作:当操作不为 4 时,把操作i连在i-1后,=4时把操作 i 连在a[i].x后: 这样建一棵树,然后遍历即可,在回溯

Codeforces Round #368 (Div. 2) ABCD

A. Brain's Photos 题解: 水得不要不要的 代码: #include<bits/stdc++.h> using namespace std; #define pb push_back #define mp make_pair #define se second #define fs first #define LL long long #define CLR(x) memset(x,0,sizeof x) #define MC(x,y) memcpy(x,y,sizeof(x)

codeforces #368

Problem A  Brain's Photos 题目大意 n行m列的矩形,每个格子有一种颜色.如果含有C.M.Y则输出#Color,否则输出#Black&White. 解题分析 = = 参考程序 1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #in

【codeforces 718E】E. Matvey&#39;s Birthday

题目大意&链接: http://codeforces.com/problemset/problem/718/E 给一个长为n(n<=100 000)的只包含‘a’~‘h’8个字符的字符串s.两个位置i,j(i!=j)存在一条边,当且仅当|i-j|==1或s[i]==s[j].求这个无向图的直径,以及直径数量. 题解:  命题1:任意位置之间距离不会大于15. 证明:对于任意两个位置i,j之间,其所经过每种字符不会超过2个(因为相同字符会连边),所以i,j经过节点至多为16,也就意味着边数至多