洛谷OJ上的A+B花(zhuang)式(bi)解法

转眼间快到了8月,一想自己都毕业好久了,很怀念曾经在各大OJ上刷题的时光,今天无意在一个算法群里看到最近有个叫洛谷的oj网站貌似蛮火的,于是注册了一个下进去看一看,顺手打开了A+B problem,然后……


洛谷OJ上的A+B花(zhuang)式(bi)解法_第1张图片


我顿时感觉我学了假的A+B……

原帖地址:https://www.luogu.org/wiki/show?name=%E9%A2%98%E8%A7%A3+P1001


作者: Treeloveswater 更新时间: 2017-03-26 15:06 举报
终于可以写一份A+B这么难的题的题解了。

咦?竟然没有人写LCT的题解?

Link-Cut Tree 会很伤心的!

ORZ为了不让LCT伤心于是我来一份LCT的A+B题解吧!

送上代码:

#include
#include
#include
#include
using namespace std;
struct node 
{
    int data,rev,sum;
    node *son[2],*pre;
    bool judge();
    bool isroot();
    void pushdown();
    void update();
    void setson(node *child,int lr);
}lct[233];
int top,a,b;
node *getnew(int x)
{
    node *now=lct+ ++top;
    now->data=x;
    now->pre=now->son[1]=now->son[0]=lct;
    now->sum=0;
    now->rev=0;
    return now;
}
bool node::judge(){return pre->son[1]==this;}
bool node::isroot()
{
    if(pre==lct)return true;
    return !(pre->son[1]==this||pre->son[0]==this);
}
void node::pushdown()
{
    if(this==lct||!rev)return;
    swap(son[0],son[1]);
    son[0]->rev^=1;
    son[1]->rev^=1;
    rev=0;
}
void node::update(){sum=son[1]->sum+son[0]->sum+data;}
void node::setson(node *child,int lr)
{
    this->pushdown();
    child->pre=this;
    son[lr]=child;
    this->update();
}
void rotate(node *now)
{
    node *father=now->pre,*grandfa=father->pre;
    if(!father->isroot()) grandfa->pushdown();
    father->pushdown();now->pushdown();
    int lr=now->judge();
    father->setson(now->son[lr^1],lr);
    if(father->isroot()) now->pre=grandfa;
    else grandfa->setson(now,father->judge());
    now->setson(father,lr^1);
    father->update();now->update();
    if(grandfa!=lct) grandfa->update();
}
void splay(node *now)
{
    if(now->isroot())return;
    for(;!now->isroot();rotate(now))
    if(!now->pre->isroot())
    now->judge()==now->pre->judge()?rotate(now->pre):rotate(now);
}
node *access(node *now)
{
    node *last=lct;
    for(;now!=lct;last=now,now=now->pre)
    {
        splay(now);
        now->setson(last,1);
    }
    return last;
}
void changeroot(node *now)
{
    access(now)->rev^=1;
    splay(now);
}
void connect(node *x,node *y)
{
    changeroot(x);
    x->pre=y;
    access(x);
}
void cut(node *x,node *y)
{
    changeroot(x);
    access(y);
    splay(x);
    x->pushdown();
    x->son[1]=y->pre=lct;
    x->update();
}
int query(node *x,node *y)
{
    changeroot(x);
    node *now=access(y);
    return now->sum;
}
int main()
{
    scanf("%d%d",&a,&b);
    node *A=getnew(a);
    node *B=getnew(b);
    //连边 Link
        connect(A,B);
    //断边 Cut
        cut(A,B);
    //再连边orz Link again
        connect(A,B);
    printf("%d\n",query(A,B)); 
    return 0;
}
作者: SW_Wind 更新时间: 2017-03-13 15:21 举报
看来还没人用Splay,赶紧水一发

因为加法满足交换律,所以我们可以把序列翻转一下,所求的总和不变

序列反转自然而然就能想到Splay啦

代码送上

//一颗资瓷区间加、区间翻转、区间求和的Splay
#include 
#define ll long long
#define N 100000
using namespace std;
int sz[N], rev[N], tag[N], sum[N], ch[N][2], fa[N], val[N];
int n, m, rt, x;
void push_up(int x){
    sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
    sum[x] = sum[ch[x][1]] + sum[ch[x][0]] + val[x];
}
void push_down(int x){
    if(rev[x]){
        swap(ch[x][0], ch[x][1]);
        if(ch[x][1]) rev[ch[x][1]] ^= 1;
        if(ch[x][0]) rev[ch[x][0]] ^= 1;
        rev[x] = 0;
    }
    if(tag[x]){
        if(ch[x][1]) tag[ch[x][1]] += tag[x], sum[ch[x][1]] += tag[x];
        if(ch[x][0]) tag[ch[x][0]] += tag[x], sum[ch[x][0]] += tag[x];
        tag[x] = 0;
    }
}
void rotate(int x, int &k){
    int y = fa[x], z = fa[fa[x]];
    int kind = ch[y][1] == x;
    if(y == k) k = x;
    else ch[z][ch[z][1]==y] = x;
    fa[x] = z; fa[y] = x; fa[ch[x][!kind]] = y;
    ch[y][kind] = ch[x][!kind]; ch[x][!kind] = y;
    push_up(y); push_up(x);
}
void splay(int x, int &k){
    while(x != k){
        int y = fa[x], z = fa[fa[x]];
        if(y != k) if(ch[y][1] == x ^ ch[z][1] == y) rotate(x, k);
        else rotate(y, k);
        rotate(x, k);
    }
}
int kth(int x, int k){
    push_down(x);
    int r = sz[ch[x][0]]+1;
    if(k == r) return x;
    if(k < r) return kth(ch[x][0], k);
    else return kth(ch[x][1], k-r);
}
void split(int l, int r){
    int x = kth(rt, l), y = kth(rt, r+2);
    splay(x, rt); splay(y, ch[rt][1]);
}
void rever(int l, int r){
    split(l, r);
    rev[ch[ch[rt][1]][0]] ^= 1;
}
void add(int l, int r, int v){
    split(l, r);
    tag[ch[ch[rt][1]][0]] += v;
    val[ch[ch[rt][1]][0]] += v;
    push_up(ch[ch[rt][1]][0]);
}
int build(int l, int r, int f){
    if(l > r) return 0;
    if(l == r){
        fa[l] = f;
        sz[l] = 1;
        return l;
    }
    int mid = l + r >> 1;
    ch[mid][0] = build(l, mid-1, mid);
    ch[mid][1] = build(mid+1, r, mid);
    fa[mid] = f;
    push_up(mid);
    return mid;
}
int asksum(int l, int r){
    split(l, r);
    return sum[ch[ch[rt][1]][0]];
}
int main(){
    //总共两个数
    n = 2;
    rt = build(1, n+2, 0);//建树
    for(int i = 1; i <= n; i++){
        scanf("%d", &x);
        add(i, i, x);//区间加
    }
    rever(1, n);//区间翻转
    printf("%d\n", asksum(1, n));//区间求和
    return 0;
}

作者: 爱国主义黑客 更新时间: 2017-03-09 19:39 举报
用一下ios::tync_with_stdio速度感觉快了很多

#include
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int a,b;
    cin>>a>>b;
    cout<

作者: 周何 更新时间: 2017-03-01 22:32 举报
看到大神们用的各种强大算法,蒟蒻我深感自己的渺小

看到许多大佬选择最短路算法,我也试着写了什么Bellman-Ford啊,SPFA啊,Dijkstra啊,Floyd啊这些算法

在这里仅给出floyd的解法,剩余三种楼下都有,我就不献丑了(其实是担心题解被驳回)

#include 
const int N=5,oo=1023741823;
int f[N][N];
inline int mn(int a,int b){
    return a2的最短路径是a,2->3的最短路径是b,那么1->3的最短路就是a+b
    floyd();
    printf ("%d",f[1][3]);//输出
    return 0;
}


作者: Num233 更新时间: 2017-02-21 21:28 举报
A+B Problem下的神犇都好多啊,鄙人实在不才几乎一半的算法都不会……

所以嘛,鄙人做这道题是用二分做的,看没有大神屑于用这个算法索性来个题解

就从数据范围里面二分范围直到找到答案为止。

#include
using namespace std;
int a,b,c;
 int main(){long long l=-int(1e9)<<1,r=int(1e9)<<1;//左边界和右边界
     scanf("%d%d",&a,&b);
     while(r-l>1){c=(l+r)>>1;//二分的步骤啦
         if(c-ba)r=c;
             else return printf("%d\n",c),0;
     }if(l!=r)return printf("%d\n",r),0;
 }


作者: KingLolierl 更新时间: 2017-02-10 10:25 举报
看到牛题解那么多,鄙人不才,只好写一个树状数组膜拜大神,神犇们勿喷~

#include
#include
using namespace std;
int lowbit(int a)
{
    return a&(-a);
}
int main()
{
    int n=2,m=1;
    int ans[m+1];
    int a[n+1],c[n+1],s[n+1];
    int o=0;
    memset(c,0,sizeof(c));
    s[0]=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        s[i]=s[i-1]+a[i];
        c[i]=s[i]-s[i-lowbit(i)];//树状数组创建前缀和优化
    }
    for(int i=1;i<=m;i++)
    {
        int q=2;
        //if(q==1)
        //{(没有更改操作)
        //    int x,y;
        //    cin>>x>>y;
        //    int j=x;
        //    while(j<=n)
        //    {
        //        c[j]+=y;
        //        j+=lowbit(j);
        //    }
        //}
        //else
        {
            int x=1,y=2;//求a[1]+a[2]的和
            int s1=0,s2=0,p=x-1;
            while(p>0)
            {
                s1+=c[p];
                p-=lowbit(p);//树状数组求和操作,用两个前缀和相减得到区间和
            }
            p=y;
            while(p>0)
            {
                s2+=c[p];
                p-=lowbit(p);
            }    
            o++;
            ans[o]=s2-s1;//存储答案
        }
    }
    for(int i=1;i<=o;i++)
        cout<



作者: frankchenfu 更新时间: 2017-01-24 22:18 举报
作为A+B Problem的第N条题解,本题解采用输入输出优化的方式。

具体可以参见这里:http://www.cnblogs.com/frankchenfu/p/6347854.html

getchar和putchar本是字符的输入和输出,但是因为快,所以更经常用于输入输出优化。下面的代码是针对非负整数的。

int s()
{
    char ch=getchar();
    int x=ch-'0';
    for(;(ch=getchar())>='0'&&ch<='9';) 
        x=x*10+ch-'0';
    return x;
}

bool w(int r)
{
    if(r>9)
        w(r/10);
    putchar(r%10+'0');
    return 1;
}
针对这题有负数,我做了一些修改。下面就是代码,呀!

#include
#define reg register
inline int s()
{
    reg char ch=getchar();
    reg int re=0;
    reg bool fl=1;
    if(ch=='-')
    {
        fl=0;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        re=re*10+ch-'0';
        ch=getchar();
    }
    return fl?re:-re;
}
inline bool w(reg int r)
{
    if(r>9)
        w(r/10);
    putchar(r%10+'0');
    return 1;
}
int main()
{
    reg int a=s(),b=s();
    if(a+b>=0)
        return !w(a+b);
    putchar('-');
    return !w(-a-b);
}
祝大家编程愉快!天天开心!

作者: jacky_chen 更新时间: 2017-01-23 23:30 举报
二进制下的a+b。如果有重复,请无视,如果没有,删了这句话

#include
#include
#include
#include
#include
using namespace std;
int main()
{
    int a,b,s=0,s1=0,i=0,na=0,nb=0;
    cin>>a>>b;
    if(a<=0) na=1,a*=-1;
    while(a!=0)
    {
        if(a%2!=0)
        s+=pow(2,a%2*i);
        a/=2;
        i++;
    }
    i=0;
    if(na==1) s*=-1;
    if(b<=0) nb=1,b*=-1;
    while(b!=0)
    {
        if(b%2!=0)
        s1+=pow(2,b%2*i);
        b/=2;
        i++;
    }
    if(nb==1) s1*=-1;
    cout<
作者: 我只会1个语言 更新时间: 2017-01-04 13:03 举报
我是一个喜欢新方法的人,在这里我就想到了等差数列,然后我们就可以用下面的新方法了。

#include
using namespace std;
int s1,s2,s3,s4;
int n,m;
int main()
{
    cin>>n>>m;
    s1=(1+n)*n/2;    算出1+2+3+...+n;
    s2=(1+n-1)*(n-1)/2;  算出1+2+3+...+(n-1);
    s3=(1+m)*m/2;    算出1+2+3+...+m;
    s4=(1+m-1)*(m-1)/2;   算出1+2+3+...+(m-1);
    cout<<(s1-s2)+(s3-s4);   输出就可以了。
    return 0;
}
你的新方法是什么呢?想到新方法就可以来这些题解哦!

作者: doby 更新时间: 2016-12-24 17:16 举报
这题是洛谷的经典啊……

这里给出一些比较基础的A+B方法

SPFA:

#include
using namespace std;
int n,m,a,b,op,head[200009],next[200009],dis[200009],len[200009],v[200009],l,r,team[200009],pd[100009],u,v1,e;
int lt(int x,int y,int z)
{
    op++,v[op]=y;
    next[op]=head[x],head[x]=op,len[op]=z;
}
int SPFA(int s,int f)//SPFA……
{
    for(int i=1;i<=200009;i++){dis[i]=999999999;}
    l=0,r=1,team[1]=s,pd[s]=1,dis[s]=0;
    while(l!=r)
    {
        l=(l+1)%90000,u=team[l],pd[u]=0,e=head[u];
        while(e!=0)
        {
            v1=v[e];
            if(dis[v1]>dis[u]+len[e])
            {
                dis[v1]=dis[u]+len[e];
                if(!pd[v1])
                {
                    r=(r+1)%90000,
                    team[r]=v1,
                    pd[v1]=1;
                }
            }
            e=next[e];
        } 
    }
    return dis[f];
}
int main()
{
    scanf("%d%d",&a,&b);
    lt(1,2,a);lt(2,3,b);//1到2为a,2到3为b,1到3即为a+b……
    printf("%d",SPFA(1,3));
    return 0;
}
Floyd:

#include
#include
using namespace std;
long long n=3,a,b,dis[4][4];
int main()
{
    cin>>a>>b;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            dis[i][j]=2147483647;
        }
    }
    dis[1][2]=a,dis[2][3]=b;
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//Floyd……
            }
        }
    }
    cout<
using namespace std;
long long a,b,c;
long long dg(long long a)
{
    if(a<=5){return a;}//防超时……
    return (dg(a/2)+dg(a-a/2));
}
int main()
{
    cin>>a>>b;
    c=dg(a)+dg(b);
    cout<
#include
using namespace std;
int main()
{
    char a1[1000],b1[1000];
      int a[1000]={0},b[1000]={0},c[1000]={0},la,lb,lc,i,x;
      cin>>a1>>b1;
      la=strlen(a1);
      lb=strlen(b1);
      for(i=0;i<=la-1;i++){a[la-i]=a1[i]-48;}
    for(i=0;i<=lb-1;i++){b[lb-i]=b1[i]-48;}
      lc=1,x=0;
    while(lc<=la||lc<=lb){c[lc]=a[lc]+b[lc]+x,x=c[lc]/10,c[lc]%=10,lc++;}
    c[lc]=x;
    if(c[lc]==0){lc--;}
    for(i=lc;i>=1;i--){cout<  
#include   
#include   
#include   
#define p 8
#define carry 100000000
using namespace std;  
const int Maxn=50001;  
char s1[Maxn],s2[Maxn];  
int a[Maxn],b[Maxn],ans[Maxn];  
int change(char s[],int n[])   
{  
    char temp[Maxn];   
    int len=strlen(s+1),cur=0;  
    while(len/p)
    {  
        strncpy(temp,s+len-p+1,p);
        n[++cur]=atoi(temp); 
        len-=p;
    }  
    if(len)
    {
        memset(temp,0,sizeof(temp));  
        strncpy(temp,s+1,len);  
        n[++cur]=atoi(temp);   
    }  
    return cur;
}  
int add(int a[],int b[],int c[],int l1,int l2)  
{  
    int x=0,l3=max(l1,l2);  
    for(int i=1;i<=l3;i++)
    {  
        c[i]=a[i]+b[i]+x;  
        x=c[i]/carry;
        c[i]%=carry;  
    }  
    while(x>0){c[++l3]=x%10;x/=10;}  
    return l3;
}  
void print(int a[],int len)  
{   
    printf("%d",a[len]);
    for(int i=len-1;i>=1;i--)printf("%0*d",p,a[i]);
    printf("\n");  
}  
int main()  
{
    scanf("%s%s",s1+1,s2+1);
    int la=change(s1,a);
    int lb=change(s2,b);
    int len=add(a,b,ans,la,lb);    
    print(ans,len);
}  

作者: XY星系质量PK 更新时间: 2016-12-18 20:06 举报
P1001题解中大神超多,用了超多超棒的算法!!!

鄙人不才,只能在这里写一个用math库的的sumsandsquares函数的程序了。。。

uses math;
var a:array[0..3] of float;
    i,p:longint;
    c,b:float;
    s:ansistring;
begin
  for i:=1 to 2 do read(a[i]);
  sumsandsquares(a,b,c);
  p:=trunc(b);
  str(p,s);
  for i:=1 to length(s) do write(s[i]);
  writeln; 
end.

作者: little_gift 更新时间: 2016-12-10 12:49 举报
P1001题解大神多啊- -然而我写了一个高精模板类

include 

using namespace std;

class cint{ //定义一个类

private:

int c_number[100001],c_len,c_d,c_fh; //属性,包括数字,长度,进制,符号

public:

        cint(); 
        ~cint();
        cint(int x); 
        cint(string st); //构造与析构函数
        cint operator+(cint& b); //重载+,以用于更方便地运算
        cint read_cint(); //读入
        void write_cint(); //输出
};
cint::cint()
{
    c_d=10;
}
cint::~cint()
{
}
cint::cint(int x)
{
    c_d=10;
    if (x<0)
    {
        c_fh=-1;
        x=-x;
    }
    else c_fh=1;
    c_len=0;
    while (x)
    {
        c_len++;
        c_number[c_len]=x%c_d;
        x/=c_d;
    }
}
cint::cint (string st)
{
    int i;
    if (st[0]=='-') 
    {
        c_fh=-1;
        st.erase(0,1);
    }
    else c_fh=1;
    while (st[0]=='0'&&st.length()>1)
        st.erase(0,1); //去除前导0
    c_len=st.length();
    for (i=1;i<=c_len;i++)
        c_number[i]=(st[c_len-i]-48)*c_fh; //将字符的ascii码-48,存入数组中
} //构造函数,将字符串存入类中
cint cint::operator+(cint& b)
{
    int i;
    cint c;
    if (c_len>=b.c_len) c.c_len=c_len;
    else c.c_len=b.c_len;
    for (i=1;i<=c.c_len;i++)
    {
        c.c_number[i]+=c_number[i]+b.c_number[i]; //将两位相加
        c.c_number[i+1]=c.c_number[i]/c.c_d;
        c.c_number[i]%=c.c_d; //处理进位
    }
    while (c.c_number[c.c_len+1])
        c.c_len++;
    return c;
} //核心部分,高精加
cint cint::read_cint()
{
    string st;
    cin>>st;
    return cint(st);
}
void cint::write_cint()
{
    int i;
    for (i=1;i<=c_len;i++)
        cout<>(istream& is,cint &c)
{
    c=c.read_cint();
    return is;
} //重载>>,便于输入
ostream& operator<<(ostream& os,cint c)
{
    c.write_cint();
    return os;
} //重载<<,便于输出.
下面是美丽的主程序

int main()
{
    cint a,b;
    cin>>a>>b;
    cout<

作者: NoNoSSoft 更新时间: 2016-11-20 21:38 举报
使用了fread和fwrite输入输出优化,速度还挺快

#include 
const size_t fSize = 1 << 15;
char iFile[fSize], *iP = iFile, oFile[fSize], *oP = oFile;
inline char readchar() {
    if (*iP && iP - iFile < fSize) { char t = *iP; iP++; return t; } else return EOF;
}
template inline void readint(T &x) {
    x = 0; char c; bool neg = 0;
    while ((c = readchar()) < '0' || c > '9') if (c == '-') neg = !neg;
    while (c >= '0' && c <= '9')
        x = x * 10 + (c ^ 48), c = readchar();
    x = neg ? -x : x;
}
inline void writechar(const char &c) { *oP = c, ++oP; }
template inline void _writeint(const T &x) {
    if (!x)
        return;
    _writeint(x / 10);
    writechar(x % 10 ^ 48);
}
template inline void writeint(T x, const char &c) {
    if (x < 0) {
        writechar('-');
        x = -x;
    }
    if (!x) {
        writechar('0');
        return;
    }
    _writeint(x);
    writechar(c);
}
int main() {
    fread(iFile, 1, fSize, stdin);
    int a, b;
    readint(a); readint(b);
    writeint(a + b, '\n');
    fwrite(oFile, 1, oP - oFile, stdout);
    return 0;
}


作者: hycuihz 更新时间: 2016-11-19 11:19 举报
看见大家都写了一大串奇怪的代码(让pascal猿表示一脸蒙逼)

于是我决定写一段最简代码

var
a,b:longint;
begin
  assign(input,'P1001.in');  //NOIP/NOI必备 不然CENA不认
  reset(input); //NOIP/NOI必备 不然CENA不认
  readln(a,b);  //输入
  close(input); //NOIP/NOI必备 不然CENA不认
  assign(output,'P1001.in'); //NOIP/NOI必备 不然CENA不认
  rewrite(output); //NOIP/NOI必备 不然CENA不认
  writeln(a+b);  //输出
  close(output); //NOIP/NOI必备 不然CENA不认
end.  //结束了啊啊啊
当然,这段代码运行会RE(因为并没有告诉我们输入输出文件名)

所以我们可以去掉输入输出文件233

var
a,b:longint;
begin
  readln(a,b);  //输入
  writeln(a+b);  //输出
end.  //结束了啊啊啊
很简单的一段源码吧

作者: zhjian 更新时间: 2016-11-15 21:23 举报
看楼下也有位运算,用递归做的,我就贴个非递归的吧。。。

#include 
int m, n;
int main()
{
    scanf("%d%d", &m, &n);
    int u = m & n;
    int v = m ^ n;
    while (u) {
        int s = v;
        int t = u << 1;
        u = s & t;
        v = s ^ t;
    }
    printf("%d\n", v);
}

作者: Zyan丶 更新时间: 2016-11-10 20:46 举报
各位大神都用网络流啊 最短路啊解这道题,那么既然是可以求最短路,为什么不可以从树上跑呢?

怀着这种想法,我冥思苦想(划掉),发现,###我可以用LCA做这道题啊~

然而鄙人不才,什么Tarjan啊ST表啊都不会,只会用一个倍增来求LCA,所以权当抛砖引玉吧。

不过我估计应该没什么想学LCA的来这道题看LCA题解吧。所以多半是写着玩~~

先说说思路(这还用说?):

建一个有三个节点的树,1为树根,2 3分别是左右儿子。

其中1 2之间的距离为a,2 3之间的距离为b,然后求1 2的LCA,和分别到LCA的距离,加起来就是1->3的最短路

其实就是题目中所求的a+b了

好吧闲话不说 上代码了(多半是个LCA的板子了):

#include                                                  //头文件
#define NI 2                                                          
//从来不喜欢算log所以一般用常数 不知道算不算坏习惯 因为3个节点 所以log3(当然以2为底)上取整得2
struct edge
{
    int to,next,data;                                              //分别表示边的终点,下一条边的编号和边的权值
}e[30];                                                                     //邻接表,点少边少开30是为了浪啊
int v[10],d[10],lca[10][NI+1],f[10][NI+1],tot=0;      //数组开到10依然为了浪
//数组还解释嘛,v表示第一条边在邻接表中的编号,d是深度,lca[x][i]表示x向上跳2^i的节点,f[x][i]表示x向上跳2^i的距离和
void build(int x,int y,int z)                                      //建边
{
    e[++tot].to=y; e[tot].data=z; e[tot].next=v[x]; v[x]=tot;
    e[++tot].to=x; e[tot].data=z; e[tot].next=v[y]; v[y]=tot;
}
void dfs(int x)                                                        //递归建树
{
    for(int i=1;i<=NI;i++)                                   //懒,所以常数懒得优化
        f[x][i]=f[x][i-1]+f[lca[x][i-1]][i-1],
        lca[x][i]=lca[lca[x][i-1]][i-1];                   //建树的同时进行预处理
    for(int i=v[x];i;i=e[i].next)                              //遍历每个连接的点
    {
        int y=e[i].to;
        if(lca[x][0]==y) continue;
        lca[y][0]=x;                                       //小技巧:lca[x][0]即为x的父亲~~(向上跳2^0=1不就是父节点嘛)
        f[y][0]=e[i].data;
        d[y]=d[x]+1;
        dfs(y);                                            //再以这个节点为根建子树【这里真的用得到嘛??】
    }
}
int ask(int x,int y)                                             //询问,也是关键
{                                                                        
    if(d[x]=0;i--)                                  //不知道能不能正着循环,好像倒着优,反正记得倒着就好了
        if(lca[x][i]!=lca[y][i])                            //如果x跳2^i和y跳2^j没跳到一起就让他们跳
            ans+=f[x][i]+f[y][i],
            x=lca[x][i],y=lca[y][i];
    return ans+f[x][0]+f[y][0];                           //跳到LCA上去(每步跳的时候都要更新信息,而且要在跳之前更新信息哦~)
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    build(1,2,a);
    build(1,3,b);                                                       //分别建1 2、1 3之间的边
    dfs(1);                                                                //以1为根建树
    printf("%d",ask(2,3));                                         //求解2 3到它们的LCA的距离和并输出
}
BINGO~~

作者: Linbom 更新时间: 2016-10-31 10:06 举报
明显的字典树

以每个数字建立字典树

建立一次查询一次

spj正负 下面上代码

#include
#include
#include
#include
using namespace std;
struct node{
    int str[26];
    int sum;
}s[1000];
char str1[100];
int t=0,tot=0,ss=0;
bool f1;
void built()
{
    t=0;
    for(int i=0;i

作者: chenleyu 更新时间: 2016-10-28 16:37 举报
一题很棒的模拟题,可以模拟人工运算的方法。

#include  
#include 
using namespace std;
int fu=1,f=1,a,b,c=0;
int main()
{
    cin>>a>>b;
    if(a<0&&b>0)fu=2;
    if(a>0&&b<0)fu=3;
    if(a<0&&b<0)f=-1;
    if(a==0){cout<b&&fu==3)f=1;
    if(b>a&&fu==3)f=-1;
    if(b>a&&fu==2)f=1;
    if(b1)c=max(a,b)-min(a,b);
    c*=f;
    cout<

作者: dph754132771 更新时间: 2016-10-28 09:08 举报
/*

P: 1001

Au: Small_Ash

表示我稍微加上了一个读入和输出优化。。。。

为什么要占坑呢,主要是发一下读入输出优化的代码

顺便给新生们传授一下c++超快的读入输出方法。。。

一般来说,c++有三种读入方式 scanf cin 以及读入优化。。。

cin 在加上ios优化之前是很慢的 scanf其次 读入优化(read)最快

以下是我做的测试数据

当读入从1开始到10^7的数列数据时:

cin耗时6.02s,scanf耗时2.23s,read只耗时0.58s

同理 cont>scanf>输出优化

对付大数据的题目这是可以用的(前提是数据输入输出都是纯数据,没有符号【包括英文字母】)

新生可以先不用弄懂实现原理,直接背就行了。这些优化NOIP是可以用的。

下面是代码
*/

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int read(){
    int out=0,fh=1;
    char cc=getchar();
    if (cc=='-') fh=-1;
    while (cc>'9'||cc<'0') cc=getchar();
    while (cc>='0'&&cc<='9') {out=out*10+cc-'0';cc=getchar();}
    return out*fh;
}
void write(int x)  
{  
    if (x==0){
        putchar('0');
        return;
    }
    int num = 0; char c[15];
    while(x) c[++num] = (x%10)+48, x /= 10;
    while(num) putchar(c[num--]);
    putchar(' '); 
}
int main(){
    write(read()+read());
    return 0;
}

作者: ghj1222 更新时间: 2016-10-27 23:01 举报
位运算cpp版的,注释已经加上了。

我认为计算机在执行的时候也是这样子的。

大意就是按照十进制竖式加法的方式来计算二进制的。先算出不进位的值(通过xor),然后算出进位(通过and),之后递归调用,两者加起来就行了

#include 
using namespace std;
int plus(int a,int b)//这个是加法运算函数
{
    if(b==0)//如果b(进位)是0(没有进位了),返回a的值
        return a;
    else
    {
        int xor,carry;
        xor=a^b;//xor是a和b不进位加法的值
        carry=(a&b)<<1;//carry是a和b进位的值(只有两个都是1才会产生进位,所以是与运算。左移一位是因为二进制加法和十进制加法竖式一样进位要加在左面一位里)
        return plus(xor,carry);//把不进位加法和进位的值的和就是结果
    }
}
int main()
{
    int a,b;
    cin >> a >> b;
    cout << plus(a,b) << endl;
    return 0;
}
正解

#include 
using namespace std;
int main()
{
    int a,b;
    cin >> a >> b;
    cout << a+b << endl;
    return 0;
}
最短代码

#include 
int main(int a,int b)
{
    return (scanf("%d%d",&a,&b),printf("%d\n",a+b))&0;
}

作者: yzz2016 更新时间: 2016-10-14 21:40 举报
//c++ 快速读入版a+b,自行体会
#include 
int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
int main()
{
    printf("%d",read()+read());
    return 0;
}

5ms , 1371kb

线段树走起

附上在下65行线段树代码

#include
#include
#include
#include
#include
#include
using namespace std;
struct node{
    int val,l,r;
};
node t[5];
int a[5],f[5];
int n,m;
void init(){
    for(int i=1;i<=2;i++){
        scanf("%d",&a[i]);
    }
}
void build(int l,int r,int node){//这是棵树
    t[node].l=l;t[node].r=r;t[node].val=0;
    if(l==r){
        f[l]=node;
        t[node].val=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,node*2);
    build(mid+1,r,node*2+1);
    t[node].val=t[node*2].val+t[node*2+1].val;
}
void update(int node){
    if(node==1)return;
    int fa=node>>1;
    t[fa].val=t[fa*2].val+t[fa*2+1].val;
    update(fa);
}
int find(int l,int r,int node){
    if(t[node].l==l&&t[node].r==r){
        return t[node].val;
    }
    int sum=0;
    int lc=node*2;int rc=lc+1;
    if(t[lc].r>=l){
        if(t[lc].r>=r){
            sum+=find(l,r,lc);
        }
        else{
            sum+=find(l,t[lc].r,lc);
        }
    }
    if(t[rc].l<=r){
        if(t[rc].l<=l){
            sum+=find(l,r,rc);
        }
        else{
            sum+=find(t[rc].l,r,rc);
        }
    }
    return sum;
}
int main(){
    init();
    build(1,2,1);
    printf("%d",find(1,2,1));
}

Dijkstra+STL的优先队列优化。48ms.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int N=405;
struct Edge {
    int v,w;
};
vector edge[N*N];
int n;
int dis[N*N];
bool vis[N*N];
struct cmp {
    bool operator()(int a,int b) {
        return dis[a]>dis[b];
    }
};
int Dijkstra(int start,int end)
{
    priority_queue,cmp> dijQue;
    memset(dis,-1,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dijQue.push(start);
    dis[start]=0;
    while(!dijQue.empty()) {
        int u=dijQue.top();
        dijQue.pop();
        vis[u]=0;
        if(u==end)
            break;
        for(int i=0; idis[u]+edge[u][i].w) {
                dis[v]=dis[u]+edge[u][i].w;
                if(!vis[v]) {
                    vis[v]=true;
                    dijQue.push(v);
                }
            }
        }
    }
    return dis[end];
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    Edge Qpush;

    Qpush.v=1;
    Qpush.w=a;
    edge[0].push_back(Qpush);

    Qpush.v=2;
    Qpush.w=b;
    edge[1].push_back(Qpush);

    printf("%d",Dijkstra(0,2));
    return 0;
}

作者: Acheing 更新时间: 2016-08-01 12:41 举报
最小生成树最好了

#include 
#include 
#define INF 2140000000
using namespace std;
struct tree{int x,y,t;}a[10];
bool cmp(const tree&a,const tree&b){return a.t

作者: xxhxhwsq 更新时间: 2016-07-25 18:22 举报
楼下说的不对

var
a,b:longint;
begin
readln(a,b);
writeln(a+b);
end.
并非唯一题解 不多说废话,附上位运算版的:

var
  a,b,ans:longint;
procedure plus(e,f:longint);
var
  x1,x2:longint;
begin
  x1:=e xor f; x2:=(e and f) shl 1;
  if e=0 then begin ans:=f; exit; end;
  If f=0 then begin ans:=e; exit; end;
  plus(x1,x2);
end;
begin
  readln(a,b);
  ans:=0;
  plus(a,b);
  writeln(ans);
end.
由于水平不高,如有错误,请各位大牛指正!

看完之后,我的表情是这样的……



你可能感兴趣的:(ACM,C/C++,转载,nine_sun算法专栏)