[NOI2009 day2 管道取珠]动态规划、巧妙转化**

【题目】http://61.187.179.132:8080/JudgeOnline/showproblem?problem_id=1566

【算法分析】

这个是看了beyondvoid大牛才会得。。。关键在第一步转化。

首先,Ai^2可以看成对于相同输出序列的结果中,进行一个N^2的枚举可得。

即:

假设Ai=n

那么

for (int i=1;i<=n;i++)

for (int j=1;j<=n;j++) ans++;

得出的ans就是Ai^2

所以就相当于走两个相同输出序列的方案数。

这样的话:

用f[x1,y1,x2,y2]表示X状态走到(x1,y1),Y状态走到(x2,y2),它们之前走的输出序列是相同的这种情况下的方案数。

((x1,y1)表示上面已经弹了x1颗珠子出来,下面已经弹出了y1颗珠子出来。)

所以有

f[x1,y1,x2,y2]=以下各项之和。

f[x1-1,y1,x2-1,y2]      前提是(u[x1]==u[x2])

f[x1-1,y1,x2,y2-1]      前提是(u[x1]==d[y2])

f[x1,y1-1,x2-1,y2]      前提是(d[y1]==u[x2])

f[x1,y1-1,x2,y2-1]      前提是(d[y1]==d[y2])

然后初始值f[0,0,0,0]=1

然后这样由于空间太吓人了,而状态X和状态Y是同步运动的,我们可以通过x1+y1-x2算出y2,于是就把第四维略去了。

三维的空间本来是可以过了,然后由于这个题库太犀利。。。数组开大了会变成system error,所以只得再搞一个滚动数组。然后没想到的是,位运算居然那么耗时,TLE掉了,然后我就先用变量把i&1和(i&1)^1存起来再做。至于里面呢,用减法代替取余是必须的,然后我看到用了好几次同一个f,每次j+1,k+1之流也许会变慢,于是我直接开指针把它表示出来。

【其它】不错,排到了第二。

Rank Run ID User Memory Time Language Code Length Submit Time 1 6774 moon5ckq 2088K 1029MS G++ 0.87K 2009-09-14 09:42:34 2 9615 edward_mj 2068K 1045MS G++ 1.42K 2010-02-19 01:16:37

【CODE】

#include

[NOI day1 2009 二叉查找树]区间动态规划

【题目大意】

给定一个Treap的结点,然后你可以修改某些权值,每修改一个权值,花费K的代价。然后整棵树的权为各点的权和,而点的权定义为深度*给定的频率。让你求修改权值+树权最小是多少。

【算法分析】

注意到一点,由于权值可以改变,所以它不一定还是满足原来性质的堆,但是由于数据值是不能改变的,所以它必然还是一颗二叉查找树

如果中序遍历一颗二叉查找树的话,就会得到一个排好序的序列。

所以可以想象如果从叶子往上面合的话,相当于每次在连续的一段里取一个结点做子树的根,然后合并这个结点两边的子树。

所以可以看成是经典的区间型动态规划。

f[i,j,W]表示[i,j]这个区间内够成一棵子树,该子树的树根的权值>=W的最小权。

然后首先有f[i,j,W]=f[i,j,W+1]

然后如果i>j的话,取为0。

剩下的就是看修不修改权值了。

f[i,j,W]=max{

f[i,k-1,W]+f[k+1,j,W]+s[i,j]+K(修改权值)

f[i,k-1,w[k]]+f[k+1,j,w[k]]+s[i,j] (前提是w[k]>=W,这就对应不修改权值)

}

【其它】WA了一遍。。。囧,memset这东西在long long身上好像有点不同,以后不用就是。

【CODE】

#include #include using namespace std;
const long long N=72;
const long long inf=(long long)(0x7FFFFFFF/2)*(long long)(0x7FFFFFFF/2);
long long n,cost;
long long key[N],w[N],ss[N],f[N][N][N],s[N][N];
long long pos[N],lw[N];

void init(){
    cin >> n >> cost;
    for (long long i=1;i<=n;i++) cin >> key[i];
    for (long long i=1;i<=n;i++) cin >> w[i];
    for (long long i=1;i<=n;i++) cin >> ss[i];
    for (long long i=1;i<=n;i++){
        pos[i]=i;
        lw[i]=w[i];
    }   
}   

void sort(){
    long long i,j,tmp;
    for (i=1;i      for (j=i+1;j<=n;j++)
        if (lw[i]>w[j]){
            tmp=lw[i]; lw[i]=lw[j]; lw[j]=tmp;
            tmp=pos[i]; pos[i]=pos[j]; pos[j]=tmp;
        }
    for (i=1;i<=n;i++) w[pos[i]]=i;
    for (i=1;i      for (j=i+1;j<=n;j++)
        if (key[i]>key[j]){
            tmp=key[i]; key[i]=key[j]; key[j]=tmp;
            tmp=w[i]; w[i]=w[j]; w[j]=tmp;
            tmp=ss[i]; ss[i]=ss[j]; ss[j]=tmp;
        }
    for (i=1;i<=n;i++){
      s[i][i]=ss[i];
      for (j=i+1;j<=n;j++)
        s[i][j]=s[i][j-1]+ss[j];
    }   
}   

void work(){
    long long len,i,j,k,W;
    for (i=1;i<=n;i++)
      for (j=1;j<=n;j++)
        f[i][j][n+1]=inf;
    for (i=0;i<=n;i++)
      for (k=1;k<=w[i];k++)
        f[i][i][k]=ss[i];
    for (len=0;len      for (i=1;i+len<=n;i++){
          j=i+len;
          for (W=n;W>=0;W–){
            f[i][j][W]=f[i][j][W+1];
            for (k=i;k<=j;k++){
              if (f[i][k-1][W]+f[k+1][j][W]+s[i][j]+cost                f[i][j][W]=f[i][k-1][W]+f[k+1][j][W]+s[i][j]+cost;
              if (w[k]>=W && f[i][k-1][w[k]]+f[k+1][j][w[k]]+s[i][j]                f[i][j][W]=f[i][k-1][w[k]]+f[k+1][j][w[k]]+s[i][j];
            }   
          }   
      }
    cout << f[1][n][1] << endl;
}   

int main(){
    freopen("treapmod.in","r",stdin);
    freopen("treapmod.out","w",stdout);
    init();
    sort();
    work();
    return 0;
}   

[NOI2005 day1 维护数列]Splay、平衡树上的线段树**

维护数列

【问题描述】

请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)

操作编号 输入文件中的格式

说明

1. 插入

INSERT_posi_tot_c1_c2_…_ctot

在当前数列的第 posi 个数字后插入 tot

个数字:c1, c2, …, ctot;若在数列首插

入,则 posi 为 0

2. 删除

DELETE_posi_tot

从当前数列的第 posi 个数字开始连续

删除 tot 个数字

3. 修改

MAKE-SAME_posi_tot_c

将当前数列的第 posi 个数字开始的连

tot 个数字统一修改为 c

4. 翻转

REVERSE_posi_tot

取出从当前数列的第 posi 个数字开始

tot 个数字,翻转后放入原来的位置

5. 求和

GET-SUM_posi_tot

计算从当前数列开始的第 posi 个数字

开始的 tot 个数字的和并输出

6. 求和最

大的子列

MAX-SUM

求出当前数列中和最大的一段子列,

并输出最大和

【输入格式】

输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M表示要进行的操作数目。

第 2 行包含 N 个数字,描述初始时的数列。

以下 M 行,每行一条命令,格式参见问题描述中的表格。

【输出格式】

对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结果,每个答案(数字)占一行。

【输入样例】

9 82 -6 3 5 1 -5 -3 6 3GET-SUM 5 4MAX-SUM INSERT 8 3 -5 7 2DELETE 12 1MAKE-SAME 3 3 2REVERSE 3 6GET-SUM 5 4MAX-SUM

【输出样例】

-110110

【样例说明】

初始时,我们拥有数列 2 -6 3 5 1 -5 -3 6 3

执行操作 GET-SUM 5 4,表示求出数列中从第 5 个数开始连续 4 个数字之和,1+(-5)+(-3)+6 = -1:

2 -6 3 5 1 -5 -3 6 3

执行操作 MAX-SUM,表示要求求出当前数列中最大的一段和,应为 3+5+1+(-5)+(-3)+6+3 = 10:

2 -6 3 5 1 -5 -3 6 3

执行操作 INSERT 8 3 -5 7 2,即在数列中第 8 个数字后插入-5 7 2,

2 -6 3 5 1 -5 -3 6 -5 7 2 3

执行操作 DELETE 12 1,表示删除第 12 个数字,即最后一个:

2 -6 3 5 1 -5 -3 6 -5 7 2

执行操作 MAKE-SAME 3 3 2,表示从第 3 个数开始的 3 个数字,统一修改为 2:

2 -6 3 5 1 -5 -3 6 -5 7 2

改为

2 -6 2 2 2 -5 -3 6 -5 7 2

执行操作 REVERSE 3 6,表示取出数列中从第 3 个数开始的连续 6 个数:

2 -6 2 2 2 -5 -3 6 -5 7 2

如上所示的灰色部分 2 2 2 -5 -3 6,翻转后得到 6 -3 -5 2 2 2,并放回原来位置:

2 -6 6 -3 -5 2 2 2 -5 7 2

最后执行 GET-SUM 5 4 和 MAX-SUM,不难得到答案 1 和 10。

2 -6 6 -3 -5 2 2 2 -5 7 2

【评分方法】

本题设有部分分,对于每一个测试点:

  • 如果你的程序能在输出文件正确的位置上打印 GET-SUM 操作的答案,你可以得到该测试点 60%的分数;
  • 如果你的程序能在输出文件正确的位置上打印 MAX-SUM 操作的答案,你可以得到该测试点 40%的分数;
  • 以上两条的分数可以叠加,即如果你的程序正确输出所有 GET-SUM 和MAX-SUM 操作的答案,你可以得到该测试点 100%的分数。

请注意:如果你的程序只能正确处理某一种操作,请确定在输出文件正确的位置上打印结果,即必须为另一种操作留下对应的行,否则我们不保证可以正确评分。

【数据规模和约定】

  • 你可以认为在任何时刻,数列中至少有 1 个数。
  • 输入数据一定是正确的,即指定位置的数在数列中一定存在。
  • 50%的数据中,任何时刻数列中最多含有 30 000 个数;
  • 100%的数据中,任何时刻数列中最多含有 500 000 个数。
  • 100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
  • 100%的数据中,M ≤20 000,插入的数字总数不超过 4 000 000 个,输入文件大小不超过 20MBytes。

【题目大意】

给定一个数列,有插入数列,删除区间,区间修改为同一个值,区间翻转,求区间和,求整个数列的最大子段和这几个操作。

【算法分析】

号称历年NOI最BT的数据结构题。

利用Splay,把要操作的区间的前驱和后继分别Splay到根和根的右结点,然后中间的部分就会聚集在根的右结点的左子树下。这样就可以进行想要的操作了。。。

然后剩下的各种操作的维护的话,你可以把这棵平衡树当成线段树来处理,不过多了一个当前结点,复杂了很多。。。

【其它】

开始在SBT上搞了个类似Splay的操作。。。但是老WA,后来想想还是直接Splay吧。。。

这题做了一整天…速度和beyondvoid的差不多,= =也许是因为我基本上模仿他的吧~

不过那个pushdown确实精妙。。。update的话,我是把维护父亲这一项都搞进去了。。。管他是不是都update一下。另外要注意的,pushdown以后的ml,mr,ms才是可用的。否则可能是虚假的。。。所以我在update里加了pushdown。另外比较猥琐的是第二个数据的话,有一个时刻数列中的数权<0,这样那个ms就要注意一下不能取null里的0值了,注意一下就成。

【CODE】

#include #include using namespace std;
const int inf=500000000;
int a[500001];

struct Splaytype{
    struct Node{
        Node *l,*r,*fa;
        int s,ms,ml,mr,sum,sn,key; // sn for samenum    mx for max_x
        bool same,rev;
    };
    Node *root,*null,sp[4000111];
    int tot;

    void update(Node *x){
        if (x==null) return;
        bool l=false,r=false;
        if (x->l!=null) {l=true; x->l->fa=x; pushdown(x->l);}
        if (x->r!=null) {r=true; x->r->fa=x; pushdown(x->r);}
        x->s=x->l->s+x->r->s+1;
        x->sum=x->l->sum+x->r->sum+x->key;
        x->ms=x->key;
        if (l) x->ms=max(x->ms,x->l->ms);
        if (r) x->ms=max(x->ms,x->r->ms);
        if (l) x->ms=max(x->ms,x->l->mr+x->key);
        if (r) x->ms=max(x->ms,x->r->ml+x->key);
        if (l && r) x->ms=max(x->ms,x->l->mr+x->r->ml+x->key);
        x->ml=x->l->sum+x->key;
        if (l) x->ml=max(x->ml,x->l->ml);
        if (r) x->ml=max(x->ml,x->l->sum+x->key+x->r->ml);
        x->mr=x->r->sum+x->key;
        if (r) x->mr=max(x->mr,x->r->mr);
        x->mr=max(x->mr,x->r->sum+x->key+x->l->mr);
    }

    void pushdown(Node *x){
        if (x==null) return;
        if (x->rev){
            x->rev=false;
            swap(x->l,x->r);
            if (x->l!=null) x->l->rev=!x->l->rev;
            if (x->r!=null) x->r->rev=!x->r->rev;
            swap(x->ml,x->mr);
        }
        if (x->same){
            x->same=false;
            if (x->l!=null) {x->l->same=true; x->l->sn=x->sn;}
            if (x->r!=null) {x->r->same=true; x->r->sn=x->sn;}
            x->key=x->sn;
            x->sum=x->s*x->key;
            x->ms=x->ml=x->mr=max(x->sum,x->key);
        }
    }

    void rotate(Node *x,char op){
        Node *y=x->fa;
        if (op==’l’){y->r=x->l; x->l=y;}
                else{y->l=x->r; x->r=y;}
        if (y->fa->l==y) y->fa->l=x;
                     else y->fa->r=x;
        x->fa=y->fa;
        update(y);
        update(x);
    }

    Node* newnode(int key){
        Node *p=&sp[++tot];
        p->l=null; p->r=null; p->fa=null;
        p->s=1; p->ms=p->ml=p->mr=p->sum=p->key=key;
        p->sn=0; p->same=false; p->rev=false;
        return p;
    }

    void init(){
        Node *p,*q;
        tot=0;
        null=&sp[0];
        null->l=null; null->r=null; null->fa=null;
        null->s=null->ms=null->ml=null->mr=null->sum=null->sn=0;
        null->same=null->rev=false; null->key=0;
        root=newnode(-inf);
        p=newnode(-inf);
        q=newnode(-inf);
        root->l=q;
        q->l=p;
        update(q);
        update(root);
    }

    void Splay(Node *x,Node *pos){
        if (x==null || x==pos) return;
        pushdown(x);
        Node *y,*z;
        while (x->fa!=pos){
            y=x->fa; z=y->fa;
            if (z==pos)
              if (y->l==x) rotate(x,’r’);
                      else rotate(x,’l’);
            else if (z->l==y)
              if (y->l==x) {rotate(y,’r’); rotate(x,’r’);}
                      else {rotate(x,’l’); rotate(x,’r’);}
            else
              if (y->r==x) {rotate(y,’l’); rotate(x,’l’);}
                      else {rotate(x,’r’); rotate(x,’l’);}
        }
    }

    Node* findpos(int pos){
        int done=0;
        Node *p=root;
        for (;;){
            pushdown(p);
            if (done+p->l->s+1==pos) return p;
            if (done+p->l->s+1                               else p=p->l;
        }
    }

    void ins(int st,int n){
        st=min(st,root->s-2);
        Node *p=findpos(st),*q=findpos(st+1),*tmp;
        Splay(p,root);
        Splay(q,p);
        for (int i=1;i<=n;i++){
            tmp=newnode(a[i]);
            if (i        }
        for (int i=1;i            tmp=&sp[tot-i];
            update(tmp);
        }
        q->l=tmp;
        update(q);
        update(p);
        update(root);
    }

    void del(int l,int r){
        r=min(r,root->s-2);
        Node *p=findpos(l-1),*q=findpos(r+1);
        Splay(p,root);
        Splay(q,p);
        q->l=null;
        update(q);
        update(p);
        update(root);
    }

    void makesame(int l,int r,int C){
        r=min(r,root->s-2);
        Node *p=findpos(l-1),*q=findpos(r+1);
        Splay(p,root);
        Splay(q,p);
        q->l->same=true;
        q->l->sn=C;
        update(q);
        update(p);
        update(root);
    }

    void reverse(int l,int r){
        r=min(r,root->s-2);
        Node *p=findpos(l-1),*q=findpos(r+1);
        Splay(p,root);
        Splay(q,p);
        q->l->rev=true;
        update(q);
        update(p);
        update(root);
    }

    int getsum(int l,int r){
        r=min(r,root->s-2);
        Node *p=findpos(l-1),*q=findpos(r+1);
        Splay(p,root);
        Splay(q,p);
        pushdown(q->l);
        return q->l->sum;
    }
}Splay;

int main(){
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    Splay.init();
    char op[100]; int n,m,pos;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    Splay.ins(1,n);
    for (int i=1;i<=m;i++){
        scanf("%s",&op);
        switch (op[0]){
            case ‘I’:
                scanf("%d%d",&pos,&n);
                for (int i=1;i<=n;i++) scanf("%d",&a[i]);
                Splay.ins(pos+1,n);
                break;
            case ‘D’:
                scanf("%d%d",&pos,&n);
                Splay.del(pos+1,pos+n);
                break;
            case ‘M’:
                if (op[2]==’K’){
                  int C;
                  scanf("%d%d%d",&pos,&n,&C);
                  Splay.makesame(pos+1,pos+n,C);
                }
                else{
                    Splay.pushdown(Splay.root);
                    printf("%dn",Splay.root->ms);
                }
                break;
            case ‘R’:
                scanf("%d%d",&pos,&n);
                Splay.reverse(pos+1,pos+n);
                break;
            case ‘G’:
                scanf("%d%d",&pos,&n);
                printf("%dn",Splay.getsum(pos+1,pos+n));
                break;
        }
    }
}

[NOI2004 郁闷的出纳员]我的第一个Splay

【算法分析】

以前用SBT做过了,不过为了学习Splay,又用它来做测试了。。。

第一次写Splay,先写了个非指针版的。。。一直WA,后来模范beyondvoid大牛的一些技巧,写了个指针版的才AC。。。

【其它】

居然比SBT快。。。

不过SBT以前用pascal写的,现在是C++,另外我觉得我的SBT使用递归也是一个重要原因吧。

【CODE】

#include const int inf=1000000000;
int limit,ss;
struct Splaytype{
    struct Splaynode{
        Splaynode *l,*r,*fa;
        int key,s;
    };   
   
    Splaynode space[1000000],*root,*p,*q,*null;
    int tot;
    void init(){
        null=&space[0];
        null->l=null;
        null->r=null;
        null->fa=null;
        null->s=0;
        tot=1;
        Splaynode *p=&space[tot];
        p->l=null;
        p->r=null;
        p->fa=null;
        p->key=inf;
        p->s=1;
        root=p;
    }   
   
    inline void update(Splaynode *x){
        if (x==null) return;
        x->s=x->l->s+x->r->s+1;
    }   
   
    void zag(Splaynode *x){
        Splaynode *y=x->fa;
        y->r=x->l;
        x->l=y;
        if (y->fa->l==y) y->fa->l=x;
                    else y->fa->r=x;
        x->fa=y->fa;
        y->fa=x;
        y->r->fa=y;
        update(y);
        update(x);
    }   
   
    void zig(Splaynode *x){
        Splaynode *y=x->fa;
        y->l=x->r;
        x->r=y;
        if (y->fa->l==y) y->fa->l=x;
                    else y->fa->r=x;
        x->fa=y->fa;
        y->fa=x;
        y->l->fa=y;
        update(y);
        update(x);
    }   
   
    void Splay(Splaynode *x,Splaynode *pos){
        if (x==root) return;
        Splaynode *y,*z;
        while (x->fa!=pos){
            y=x->fa; z=y->fa;
            if (z==pos)
              if (y->l==x) zig(x);
                      else zag(x);
            else if (z->l==y)
              if (y->l==x) {zig(y); zig(x);}
                      else {zag(x); zig(x);}
            else
              if (y->r==x) {zag(y); zag(x);}
                      else {zig(x); zag(x);}
        }
    }   
   
    void ins(int key){
        p=root->l,q=root;
        for (;;){
            if (p==null){
                p=&space[++tot];
                p->l=null;
                p->r=null;
                p->s=1;
                p->key=key;
                p->fa=q;
                if (key                           else q->r=p;
                break;
            }else
            if (key                q=p;
                p=p->l;
            }   
            else{
                q=p;
                p=p->r;
            }   
        }
        q=p;
        for (;p!=null;p=p->fa) update(p);
        Splay(q,root);
    }   
   
    void del(){
        p=root->l; q=root;
        for (;;){
            if (p==null){
                Splay(q,root);
                if (q->key+ss                    root->l=q->r;
                    if (q->r!=null) q->r->fa=root;
                    update(root);
                }
                else{
                    q->l=null;
                    update(q);
                    update(root);
                }   
                return;
            }else
            if (p->key+ss>=limit){
                q=p;
                p=p->l;
            }   
            else{
                q=p;
                p=p->r;
            }   
        }   
    }
   
    int get(int rank){
        if (rank>root->s) return -1;
        int done=0,td;
        p=root;
        for (;;){
            if (done+p->r->s+1==rank) return p->key+ss;
            if (done+p->r->s+1>rank) p=p->r;
            else{
                done+=p->r->s+1;
                p=p->l;
            }   
        }   
    }   
}Splay;

int main(){
    freopen("cashier.in","r",stdin);
    freopen("cashier.out","w",stdout);
    Splay.init();
    int n,x,innum=1; char ch;
    scanf("%d%d",&n,&limit);
    for (int i=1;i<=n;i++){
        for (ch=getchar();ch==’ ‘ || ch==’n’;ch=getchar());
        scanf("%d",&x);
        switch (ch){
            case ‘I’:if (x            case ‘A’:ss+=x; Splay.del(); break;
            case ‘S’:ss-=x; Splay.del(); break;
            case ‘F’:printf("%dn",Splay.get(x+1)); break;
        }   
    }   
    printf("%dn",innum-Splay.root->s);
}   

[BSOI 1156]半平面交

【题目大意】

给出N个凸多边形(坐标按逆时针给出),让你求面积交。

【其它】1A

194906 edward_mj 1156 Accepted 184K 15MS G++ 1.73K 2010-02-15 17:53:10

【CODE】

#include #include struct point{double x,y;};
struct line{double a,b,c;};
point p[1000000],pt[1000000],pre,now,st,O;
int n,tot;

void init(){
     O.x=0; O.y=0;
     scanf("%d%d",&tot,&n);
     for (int i=1;i<=n;i++)
         scanf("%lf%lf",&p[i].x,&p[i].y);
}

double X(point p0,point p1,point p2){
       return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}

line getline(point p1,point p2){
     line New;
     New.a=p1.y-p2.y;
     New.b=p2.x-p1.x;
     New.c=X(p1,p2,O);
     return New;
}

point jiaodian(point p1,point p2,point p3,point p4){
      point New;
      line l1=getline(p1,p2),l2=getline(p3,p4);
      double tmp=l1.a*l2.b-l2.a*l1.b;
      New.x=(l1.b*l2.c-l2.b*l1.c)/tmp;
      New.y=-(l1.a*l2.c-l2.a*l1.c)/tmp;
      return New;
}

void cut(){
     int N=0;
     p[n+1]=p[1];
     for (int i=2;i<=n+1;i++)
       if (X(pre,now,p[i-1])<0){
            if (X(pre,now,p[i])>0)
              pt[++N]=jiaodian(pre,now,p[i-1],p[i]);
       }
       else{
            pt[++N]=p[i-1];
            if (X(pre,now,p[i])<0)
              pt[++N]=jiaodian(pre,now,p[i-1],p[i]);
       }
     for (int i=1;i<=N;i++) p[i]=pt[i];
     n=N;
}

void work(){
     int m;
     for (int i=1;i       scanf("%d",&m);
       scanf("%lf%lf",&st.x,&st.y);
       pre=st;
       for (int i=1;i           scanf("%lf%lf",&now.x,&now.y);
           cut();
           pre=now;
       }
       now=st;
       cut();
     }
}

void print(){
     p[n+1]=p[1];
     double ans=0;
     for (int i=1;i<=n;i++)
       ans+=(p[i].x*p[i+1].y-p[i+1].x*p[i].y)/2;
     ans=fabs(ans);
     printf("%.3lfn",ans);
}

int main(){
    init();
    work();
    print();
}