找段错误找了一个小时,纪念一下

Posted 江柏英的技术博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了找段错误找了一个小时,纪念一下相关的知识,希望对你有一定的参考价值。

题目链接:https://pintia.cn/problem-sets/994805342720868352/exam/problems/994805344776077312

你猜怎么着,我把M看成了N,N<300,我数组就开了1000,我甚至觉得很够了已经,结果人家M的范围压根没给,后来算算大概有5万。抛了个段错误我还一直以为是测试数据有问题,蠢死我了!!

这题我一开始按照dfs的套路去做了,但是最后一个节点超时了我靠:

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<cstring>
#include<unordered_map>
using namespace std;

#define inf 0x3f3f3f3f 

struct edge 
    string to;
    int next;
 g[50000];
int head[301], cnt;
string s, t;
unordered_map<string, int> M;
vector<vector<string> > res;
vector<string> path;
int vis[301], gender[301];

void dfs(string cur, int cur_step) 
    if (cur_step == 4) 
        // 找到
        res.push_back(path);
        return ;
    
    if (cur_step == 1) 
        // 找和A同性的
        for (int i = head[M[cur]]; i; i = g[i].next) 
            string to = g[i].to;
            if (!vis[M[to]] && gender[M[to]] == gender[M[s]] && to != t) 
                vis[M[to]] = 1;
                path.push_back(to[0] == \'-\' ? to.substr(1, to.size() - 1) : to);
                dfs(to, cur_step + 1);
                path.pop_back();
                vis[M[to]] = 0;
            
        
     else if (cur_step == 2)
        // 找和B同性的
        for (int i = head[M[cur]]; i; i = g[i].next) 
            string to = g[i].to;
            if (!vis[M[to]] && gender[M[to]] == gender[M[t]] && to != t) 
                vis[M[to]] = 1;
                path.push_back(to[0] == \'-\' ? to.substr(1, to.size() - 1) : to);
                dfs(to, cur_step + 1);
                path.pop_back();
                vis[M[to]] = 0;
            
        
     else if (cur_step == 3) 
        // 找B
        for (int i = head[M[cur]]; i; i = g[i].next) 
            string to = g[i].to;
            if (!vis[M[to]] && to == t) 
                vis[M[to]] = 1;
                dfs(to, cur_step + 1);
                vis[M[to]] = 0;
            
        
    

bool cmp(vector<string> &a, vector<string> &b) 
    return (a[0] < b[0]) || (a[0] == b[0] && a[1] < b[1]);

void output() 
    for (int i = 0; i < res.size(); i++) 
        cout << res[i][0] << " " << res[i][1] << endl;
    

int n, m, k, num;
int main() 
    cin >> n>> m;

    for (int i = 0; i < m; i++) 
        string a, b;
        cin >> a >> b;
        if (M.find(a) == M.end()) 
            M[a] = ++num;
        
        if (M.find(b) == M.end()) 
            M[b] = ++num;
        
        g[++cnt] = edgeb, head[M[a]];
        head[M[a]] = cnt;

        g[++cnt] = edgea, head[M[b]];
        head[M[b]] = cnt;

        gender[M[b]] = (b[0] != \'-\');
        gender[M[a]] = (a[0] != \'-\');
    
    cin >> k;
    for (int i = 0; i < k; i++) 
        cin >> s >> t;
        if (M.find(s) == M.end()) 
            cout << 0 << endl;
            continue;
        
        memset(vis, 0, sizeof(vis));
        vis[M[s]] = 1;
        path.clear();
        res.clear();
        dfs(s, 1);
        sort(res.begin(), res.end(), cmp);
        printf("%d\\n", res.size());
        output();
    
    return 0;

没办法,两个半小时的苦苦挣扎之后再叫我再去优化代码,我可不干了。换个思路吧,看看柳神的代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;
unordered_map<int, bool> arr;
struct node  // vector + 结构体就好了,妈的,我在搞什么二维的vector,多捞啊
    int a, b;
;
bool cmp(node x, node y) 
    return x.a != y.a ? x.a < y.a : x.b < y.b; // 三元表达式的写法,嘿嘿,学到了

int main() 
    int n, m, k;
    scanf("%d%d", &n, &m);
    vector<int> v[10000];
    for (int i = 0; i < m; i++) 
        string a, b;
        cin >> a >> b;
        if (a.length() == b.length())  // 邻接表记录同性朋友,思路是真的清晰!
            v[abs(stoi(a))].push_back(abs(stoi(b))); // stoi() 这玩意为啥总是记不住?有前导零也不怕,照样盘它!
            v[abs(stoi(b))].push_back(abs(stoi(a)));
        
        arr[abs(stoi(a)) * 10000 + abs(stoi(b))] = arr[abs(stoi(b)) * 10000 + abs(stoi(a))] = true; // 邻接矩阵一维化,有效地节省了空间,秀我一脸。。。
        // 连等是个技巧
    
    scanf("%d", &k);
    for (int i = 0; i < k; i++) 
        int c, d;
        cin >> c >> d;
        vector<node> ans;
        for (int j = 0; j < v[abs(c)].size(); j++) 
            for (int k = 0; k < v[abs(d)].size(); k++) 
                if (v[abs(c)][j] == abs(d) || abs(c) == v[abs(d)][k]) continue; // 朋友总不能直接是对象吧,也不能是自己吧,PASS PASS
                if (arr[v[abs(c)][j] * 10000 + v[abs(d)][k]] == true)
                    ans.push_back(nodev[abs(c)][j], v[abs(d)][k]);  // 我的朋友和你的朋友是不是朋友呢?两个for循环 woc 多么省力啊,我还搁那 dfs 半天写不清楚
            
        
        sort(ans.begin(), ans.end(), cmp); // 排完序就出来了,over!!
        printf("%d\\n", int(ans.size()));
        for(int j = 0; j < ans.size(); j++)
            printf("%04d %04d\\n", ans[j].a, ans[j].b); // 千万记得格式 %04d 上一题我就栽在这里了,耗了半个小时才发现
    
    return 0;

JZOJ4238 纪念碑

Description
2034年,纪念中学决定修建校庆100周年纪念碑,作为杰出校友的你被找了过来,帮校方确定纪念碑的选址.
纪念中学的土地可以看作是一个长为n,宽为m的矩形.它由n* m个1*1的正方形组成,其中左下角的正方形的坐标为(1,1),右上角的正方形的坐标为(n, m).其中有一些土地已经被用来修建建筑物,每一幢建筑物都可以看做是一个左下角为(x1,y1),右上角为(x2,y2)的矩形.
纪念碑可以看作是一个正方形.校方希望你找出一块最大的正方形区域供他们参考.

Input
每一组数据的第一行包含三个整数n,m和p,分别表示学校的长,宽以及建筑物的数量.
接下来的p行,每行包含四个整数x1,y1,x2,y2,分别表示每一幢建筑物左下角以及右上角的坐标.

Output
输出一个数,表示可能的最大边长.

Sample Input
13 5 8
8 4 10 4
4 3 4 4
10 2 12 2
8 2 8 4
2 4 6 4
10 3 10 4
12 3 12 4
2 2 4 2

Sample Output
3

Data Constraint
对于30%的数据,p<=1000.
对于70%的数据,p<=30000.
对于100%的数据,p<=400000,m,n<=1000000.

分析:
如果我们确定了上下界,那么左右界最大就可以用线段树维护
设mx为整个区间最长空段,lmx为左端点出发最长空段,rmx为右端点出发最长空段
这三个值可以进行懒标记维护并向上递推
上下界考虑扫描线
目前上下界为L和R,最长左右界为S
考虑拓宽R,如果R-L+1>=S,则可以拓宽R
否则便缩小L,帮助拓宽R

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>

#define maxn 1000005
#define pii pair<int,int>
#define mp make_pair

using namespace std;

inline int getint()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

int n,m;
int len[maxn<<2],lmx[maxn<<2],rmx[maxn<<2],mx[maxn<<2],lz[maxn<<2];
vector<pii>l[maxn],r[maxn];
int ans;

inline void pushup(int i)
{
    mx[i]=max(max(mx[i<<1],mx[i<<1|1]),rmx[i<<1]+lmx[i<<1|1]);
    lmx[i]=(lmx[i<<1]==len[i<<1]?len[i<<1]+lmx[i<<1|1]:lmx[i<<1]);
    rmx[i]=(rmx[i<<1|1]==len[i<<1|1]?len[i<<1|1]+rmx[i<<1]:rmx[i<<1|1]);
}

inline void work(int i,int x){mx[i]=lmx[i]=rmx[i]=x;}

inline void pushdown(int i)
{
    if(lz[i])
    {
        if(~lz[i])lz[i<<1|1]=lz[i<<1]=lz[i],work(i<<1,0),work(i<<1|1,0);
        else lz[i<<1|1]=lz[i<<1]=lz[i],work(i<<1,len[i<<1]),work(i<<1|1,len[i<<1|1]);
        lz[i]=0;
    }
}

inline void build(int i,int l,int r)
{
    mx[i]=lmx[i]=rmx[i]=len[i]=r-l+1;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(i<<1,l,mid),build(i<<1|1,mid+1,r);
}

inline void update(int i,int l,int r,int ql,int qr,int op)
{
    if(qr<l||r<ql)return;
    if(ql<=l&&r<=qr)
    {
        if(~op)work(i,0),lz[i]=op;
        else work(i,len[i]),lz[i]=op;
        return;
    }
    pushdown(i);
    int mid=(l+r)>>1;
    update(i<<1,l,mid,ql,qr,op),update(i<<1|1,mid+1,r,ql,qr,op);
    pushup(i);
}

int main()
{
    n=getint(),m=getint();int tmp=getint();
    while(tmp--)
    {
        int x1=getint(),y1=getint(),x2=getint(),y2=getint();
        l[x1].push_back(mp(y1,y2)),r[x2].push_back(mp(y1,y2));
    }
    build(1,1,m);
    int L=1;
    for(int R=1;R<=n;R++)
    {
        for(int i=0;i<l[R].size();i++)update(1,1,m,l[R][i].first,l[R][i].second,1);
        ans=max(ans,min(mx[1],R-L+1));
        while(R-L+1>mx[1])
        {
            for(int i=0;i<r[L].size();i++)update(1,1,m,r[L][i].first,r[L][i].second,-1);
            L++;
        }
    }
    printf("%d
",ans);
}

技术图片

以上是关于找段错误找了一个小时,纪念一下的主要内容,如果未能解决你的问题,请参考以下文章

纪念一下我对Kalman的无限崇拜之情

JZOJ4238 纪念碑

第一爬成功,纪念一下

[扫描线][线段树]JZOJ 4238 纪念碑

第一次盲拧魔方成功,纪念一下

[扫描线][差分约束] Jzoj P4238 纪念碑